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().ModulesValidateOncePerBuildSession)
402 ScanInvocation->getHeaderSearchOpts().BuildSessionTimestamp =
404
405 ScanInvocation->getFrontendOpts().DisableFree = false;
406 ScanInvocation->getFrontendOpts().GenerateGlobalModuleIndex = false;
407 ScanInvocation->getFrontendOpts().UseGlobalModuleIndex = false;
408 ScanInvocation->getFrontendOpts().GenReducedBMI = false;
409 ScanInvocation->getFrontendOpts().ModuleOutputPath.clear();
410 // This will prevent us compiling individual modules asynchronously since
411 // FileManager is not thread-safe, but it does improve performance for now.
412 ScanInvocation->getFrontendOpts().ModulesShareFileManager = true;
413 ScanInvocation->getHeaderSearchOpts().ModuleFormat = "raw";
414 ScanInvocation->getHeaderSearchOpts().ModulesIncludeVFSUsage =
415 any(Service.getOpts().OptimizeArgs & ScanningOptimizations::VFS);
416
417 // Consider different header search and diagnostic options to create
418 // different modules. This avoids the unsound aliasing of module PCMs.
419 //
420 // TODO: Implement diagnostic bucketing to reduce the impact of strict
421 // context hashing.
422 ScanInvocation->getHeaderSearchOpts().ModulesStrictContextHash = true;
423 ScanInvocation->getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
424 ScanInvocation->getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
425 ScanInvocation->getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
426 ScanInvocation->getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
427 true;
428 ScanInvocation->getHeaderSearchOpts().ModulesForceValidateUserHeaders = false;
429
430 // Avoid some checks and module map parsing when loading PCM files.
431 ScanInvocation->getPreprocessorOpts().ModulesCheckRelocated = false;
432
433 // FIXME: Do this even with PCHs by marking the option as something like
434 // "preprocessor benign" in LangOptions.def so that it passes the
435 // compatibility checks in ASTReader.
436 if (ScanInvocation->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
437 // Application extension only affects the handling of availability
438 // attributes, which cannot change the dependencies.
439 ScanInvocation->getLangOpts().AppExt = false;
440 }
441
442 // Ensure that the scanner does not create new dependency collectors,
443 // and thus won't write out the extra '.d' files to disk.
444 ScanInvocation->getDependencyOutputOpts() = {};
445
446 Controller.initializeScanInvocation(*ScanInvocation);
447
448 return ScanInvocation;
449}
450
453 // Create a collection of stable directories derived from the ScanInstance
454 // for determining whether module dependencies would fully resolve from
455 // those directories.
457 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
458 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
459 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
460 return StableDirs;
461}
462
463static std::optional<PrebuiltModulesAttrsMap>
465 llvm::SmallVector<StringRef> &StableDirs) {
466 // Store a mapping of prebuilt module files and their properties like header
467 // search options. This will prevent the implicit build to create duplicate
468 // modules and will force reuse of the existing prebuilt module files
469 // instead.
470 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
471
472 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
474 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance,
476 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
477 return {};
478
479 return PrebuiltModulesASTMap;
480}
481
482static std::unique_ptr<DependencyOutputOptions>
484 auto Opts = std::make_unique<DependencyOutputOptions>(
485 Invocation.getDependencyOutputOpts());
486 // We need at least one -MT equivalent for the generator of make dependency
487 // files to work.
488 if (Opts->Targets.empty())
489 Opts->Targets = {deduceDepTarget(Invocation.getFrontendOpts().OutputFile,
490 Invocation.getFrontendOpts().Inputs)};
491 Opts->IncludeSystemHeaders = true;
492
493 return Opts;
494}
495
496static std::shared_ptr<ModuleDepCollector>
498 CompilerInstance &ScanInstance,
499 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
501 DependencyActionController &Controller,
502 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
503 SmallVector<StringRef> &StableDirs) {
504 auto MDC = std::make_shared<ModuleDepCollector>(
505 Service, std::move(DepOutputOpts), ScanInstance, Controller, Inv,
506 std::move(PrebuiltModulesASTMap), StableDirs);
507 ScanInstance.addDependencyCollector(MDC);
508 return MDC;
509}
510
511namespace {
512/// Manages (and terminates) the asynchronous compilation of modules.
513class AsyncModuleCompiles {
514 std::mutex Mutex;
515 bool Stop = false;
516 // FIXME: Have the service own a thread pool and use that instead.
517 std::vector<std::thread> Compiles;
518
519public:
520 /// Registers the module compilation, unless this instance is about to be
521 /// destroyed.
522 void add(llvm::unique_function<void()> Compile) {
523 std::lock_guard<std::mutex> Lock(Mutex);
524 if (!Stop)
525 Compiles.emplace_back(std::move(Compile));
526 }
527
528 ~AsyncModuleCompiles() {
529 {
530 std::lock_guard<std::mutex> Lock(Mutex);
531 Stop = true;
532 }
533 for (std::thread &Compile : Compiles)
534 Compile.join();
535 }
536};
537
538struct SingleModuleWithAsyncModuleCompiles : PreprocessOnlyAction {
539 DependencyScanningService &Service;
540 DependencyActionController &Controller;
541 AsyncModuleCompiles &Compiles;
542
543 SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service,
544 DependencyActionController &Controller,
545 AsyncModuleCompiles &Compiles)
546 : Service(Service), Controller(Controller), Compiles(Compiles) {}
547
548 bool BeginSourceFileAction(CompilerInstance &CI) override;
549};
550
551/// Runs the preprocessor on a TU with single-module-parse-mode and compiles
552/// modules asynchronously without blocking or importing them.
553struct SingleTUWithAsyncModuleCompiles : PreprocessOnlyAction {
554 DependencyScanningService &Service;
555 DependencyActionController &Controller;
556 AsyncModuleCompiles &Compiles;
557
558 SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service,
559 DependencyActionController &Controller,
560 AsyncModuleCompiles &Compiles)
561 : Service(Service), Controller(Controller), Compiles(Compiles) {}
562
563 bool BeginSourceFileAction(CompilerInstance &CI) override;
564};
565
566/// The preprocessor callback that takes care of initiating an asynchronous
567/// module compilation if needed.
568struct AsyncModuleCompile : PPCallbacks {
569 CompilerInstance &CI;
570 DependencyScanningService &Service;
571 DependencyActionController &Controller;
572 AsyncModuleCompiles &Compiles;
573
574 AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service,
575 DependencyActionController &Controller,
576 AsyncModuleCompiles &Compiles)
577 : CI(CI), Service(Service), Controller(Controller), Compiles(Compiles) {}
578
579 void moduleLoadSkipped(Module *M) override {
580 M = M->getTopLevelModule();
581
582 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
583 ModuleCache &ModCache = CI.getModuleCache();
584 ModuleFileName ModuleFileName = HS.getCachedModuleFileName(M);
585
586 uint64_t Timestamp = ModCache.getModuleTimestamp(ModuleFileName);
587 // Someone else already built/validated the PCM.
588 if (Timestamp > CI.getHeaderSearchOpts().BuildSessionTimestamp)
589 return;
590
591 if (!CI.getASTReader())
592 CI.createASTReader();
593 SmallVector<ASTReader::ImportedModule, 0> Imported;
594 // Only calling ReadASTCore() to avoid the expensive eager deserialization
595 // of the clang::Module objects in ReadAST().
596 // FIXME: Consider doing this in the new thread depending on how expensive
597 // the read turns out to be.
598 switch (CI.getASTReader()->ReadASTCore(
599 ModuleFileName, serialization::MK_ImplicitModule, SourceLocation(),
600 nullptr, Imported, {}, {}, {},
604 // We successfully read a valid, up-to-date PCM.
605 // FIXME: This could update the timestamp. Regular calls to
606 // ASTReader::ReadAST() would do so unless they encountered corrupted
607 // AST block, corrupted extension block, or did not read the expected
608 // top-level module.
609 return;
612 // The most interesting case.
613 break;
614 default:
615 // Let the regular scan diagnose this.
616 return;
617 }
618
619 auto Lock = ModCache.getLock(ModuleFileName);
620 bool Owned;
621 llvm::Error LockErr = Lock->tryLock().moveInto(Owned);
622 // Someone else is building the PCM right now.
623 if (!LockErr && !Owned)
624 return;
625 // We should build the PCM.
626 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
627 llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
628 Service, Service.getOpts().MakeVFS());
629 VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
630 CI.getDiagnostics(), std::move(VFS));
631 auto DC = std::make_unique<DiagnosticConsumer>();
632 auto MC = makeInProcessModuleCache(Service.getModuleCacheEntries(),
633 Service.getLogger());
634 CompilerInstance::ThreadSafeCloneConfig CloneConfig(std::move(VFS), *DC,
635 std::move(MC));
636 auto ModCI1 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
637 CloneConfig);
638 auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
639 CloneConfig);
640
641 auto ModController = Controller.clone();
642
643 // Note: This lock belongs to a module cache that might not outlive the
644 // thread. This works, because the in-process lock only refers to an object
645 // managed by the service, which does outlive the thread.
646 Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
647 ModCI2 = std::move(ModCI2), DC = std::move(DC),
648 ModController = std::move(ModController), Service = &Service,
649 Compiles = &Compiles] {
650 llvm::CrashRecoveryContext CRC;
651 (void)CRC.RunSafely([&] {
652 // Quickly discovers and compiles modules for the real scan below.
653 SingleModuleWithAsyncModuleCompiles Action1(*Service, *ModController,
654 *Compiles);
655 (void)ModCI1->ExecuteAction(Action1);
656 // The real scan below.
657 ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
658 GenerateModuleFromModuleMapAction Action2;
659 (void)ModCI2->ExecuteAction(Action2);
660 });
661 });
662 }
663};
664
665bool SingleModuleWithAsyncModuleCompiles::BeginSourceFileAction(
666 CompilerInstance &CI) {
669 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
670 return true;
671}
672
673bool SingleTUWithAsyncModuleCompiles::BeginSourceFileAction(
674 CompilerInstance &CI) {
677 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
678 return true;
679}
680} // namespace
681
684 DependencyActionController &Controller,
685 AsyncModuleCompiles &Compiles) {
686 SingleTUWithAsyncModuleCompiles Action(Service, Controller, Compiles);
687 (void)PrescanCI.ExecuteAction(Action);
688}
689
690namespace clang {
691namespace dependencies {
692
693std::unique_ptr<DiagnosticOptions>
695 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
696 llvm::transform(CommandLine, CCommandLine.begin(),
697 [](const std::string &Str) { return Str.c_str(); });
698 auto DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
699 sanitizeDiagOpts(*DiagOpts);
700 return DiagOpts;
701}
702
703class CompilerInstanceWithContext {
704 // Context
706 llvm::StringRef CWD;
707 std::vector<std::string> CommandLine;
708
709 // Context - compiler invocation
710 std::unique_ptr<CompilerInvocation> OriginalInvocation;
711
712 // Context - output options
713 std::unique_ptr<DependencyOutputOptions> OutputOpts;
714
715 // Context - stable directory handling
717 PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
718
719 // Context - used by AsyncScan's prescan pass
721
722 // Compiler Instance
723 std::unique_ptr<CompilerInstance> CIPtr;
724
725 // Source location offset.
726 int32_t SrcLocOffset = 0;
727
728 CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,
730 : Worker(Worker), CWD(CWD), CommandLine(CMD.begin(), CMD.end()) {}
731
732 bool initialize(DependencyActionController &Controller,
733 DiagnosticsEngine &DiagEngine,
735 {
736 auto LogLine = Worker.Service.getLogger().log();
737 LogLine.logArray("init_compiler_instance_with_context:", " ",
738 CommandLine);
739 }
740
741 ScanFS = Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
742 OriginalInvocation = createCompilerInvocation(CommandLine, DiagEngine);
743 if (!OriginalInvocation) {
744 DiagEngine.Report(diag::err_fe_expected_compiler_job)
745 << llvm::join(CommandLine, " ");
746 return false;
747 }
748
749 return initializeScanInstance(Controller, DiagEngine.getClient());
750 }
751
752 bool initializeScanInstance(DependencyActionController &Controller,
753 DiagnosticConsumer *DiagConsumer) {
754 assert(OriginalInvocation && ScanFS &&
755 "OriginalInvocation and ScanFS must be set before this call");
756
757 if (any(Worker.Service.getOpts().OptimizeArgs &
759 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
760
761 // Create the CompilerInstance.
762 std::shared_ptr<ModuleCache> ModCache = makeInProcessModuleCache(
763 Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
764 CIPtr = std::make_unique<CompilerInstance>(
765 createScanCompilerInvocation(*OriginalInvocation, Worker.Service,
766 Controller),
767 Worker.PCHContainerOps, std::move(ModCache));
768 auto &CI = *CIPtr;
769
770 initializeScanCompilerInstance(CI, ScanFS, DiagConsumer, Worker.Service,
771 Worker.DepFS);
772
773 StableDirs = getInitialStableDirs(CI);
774 auto MaybePrebuiltModulesASTMap =
775 computePrebuiltModulesASTMap(CI, StableDirs);
776 if (!MaybePrebuiltModulesASTMap)
777 return false;
778
779 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
780 OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
781
782 // We do not create the target in initializeScanCompilerInstance because
783 // setting it here is unique for by-name lookups. We create the target only
784 // once here, and the information is reused for all computeDependencies
785 // calls. We do not need to call createTarget explicitly if we go through
786 // CompilerInstance::ExecuteAction to perform scanning.
787 return CI.createTarget();
788 }
789
790 bool prescanModulesAsync(AsyncModuleCompiles &Compiles,
791 DependencyActionController &Controller) {
792 auto ModCache = makeInProcessModuleCache(
793 Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
794 CompilerInstance PrescanCI(
795 std::make_shared<CompilerInvocation>(CIPtr->getInvocation()),
796 Worker.PCHContainerOps, std::move(ModCache));
797
798 DiagnosticConsumer DiagConsumer;
799 initializeScanCompilerInstance(PrescanCI, ScanFS, &DiagConsumer,
800 Worker.Service, Worker.DepFS);
801
802 // FIXME: reuse the StableDirs/PrebuiltModuleASTMap computed in
803 // initialize().
804 SmallVector<StringRef> PrescanStableDirs = getInitialStableDirs(PrescanCI);
805 if (!computePrebuiltModulesASTMap(PrescanCI, PrescanStableDirs))
806 return false;
807
809 PrescanCI.getLangOpts().CompilingPCH = true;
810
811 runTUModulePrescan(PrescanCI, Worker.Service, Controller, Compiles);
812 return true;
813 }
814
815public:
816 static std::optional<CompilerInstanceWithContext>
818 DependencyScanningWorker &Worker, StringRef CWD,
819 ArrayRef<std::string> CC1CommandLine, DiagnosticsEngine &DiagEngine,
821 DependencyActionController &Controller) {
822 CompilerInstanceWithContext CIWC(Worker, CWD, CC1CommandLine);
823 if (!CIWC.initialize(Controller, DiagEngine, std::move(OverlayFS)))
824 return std::nullopt;
825 return std::move(CIWC);
826 }
827
828 bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer,
829 DependencyActionController &Controller) {
830 Worker.Service.getLogger().log() << "start scan_by_name: " << ModuleName;
831 llvm::scope_exit ExitLogging([&] {
832 Worker.Service.getLogger().log() << "finish scan_by_name: " << ModuleName;
833 });
835 llvm::report_fatal_error("exceeded maximum by-name scans for worker");
836
837 assert(CIPtr && "CIPtr must be initialized before calling this method");
838 auto &CI = *CIPtr;
839
840 // We need to reset the diagnostics, so that the diagnostics issued
841 // during a previous computeDependencies call do not affect the current
842 // call. If we do not reset, we may inherit fatal errors from a previous
843 // call.
844 CI.getDiagnostics().Reset();
845
846 // We create this cleanup object because computeDependencies may exit
847 // early with errors.
848 llvm::scope_exit CleanUp([&]() {
850 // The preprocessor may not be created at the entry of this method,
851 // but it must have been created when this method returns, whether
852 // there are errors during scanning or not.
854 });
855
857 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
858 Worker.Service,
859 /* The MDC's constructor makes a copy of the OriginalInvocation, so
860 we can pass it in without worrying that it might be changed across
861 invocations of computeDependencies. */
862 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
863
864 CompilerInvocation ModuleInvocation(*OriginalInvocation);
865 if (!Controller.initialize(CI, ModuleInvocation))
866 return false;
867
868 if (!SrcLocOffset) {
869 // When SrcLocOffset is zero, we are at the beginning of the fake source
870 // file. In this case, we call BeginSourceFile to initialize.
871 std::unique_ptr<FrontendAction> Action =
872 std::make_unique<PreprocessOnlyAction>();
873 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
874 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
875 assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
876 (void)ActionBeginSucceeded;
877 }
878
879 Preprocessor &PP = CI.getPreprocessor();
881 FileID MainFileID = SM.getMainFileID();
882 SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
883 SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
884 PPCallbacks *CB = nullptr;
885 if (!SrcLocOffset) {
886 // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
887 // the preprocessor.
888 bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
889 assert(!PPFailed && "Preprocess must be able to enter the main file.");
890 (void)PPFailed;
891 CB = MDC->getPPCallbacks();
892 } else {
893 // When SrcLocOffset is non-zero, the preprocessor has already been
894 // initialized through a previous call of computeDependencies. We want to
895 // preserve the PP's state, hence we do not call EnterSourceFile again.
896 MDC->attachToPreprocessor(PP);
897 CB = MDC->getPPCallbacks();
898
899 FileID PrevFID;
901 SM.getFileCharacteristic(IDLocation);
902 CB->LexedFileChanged(MainFileID,
904 FileType, PrevFID, IDLocation);
905 }
906
907 // FIXME: Scan modules asynchronously here as well.
908
909 SrcLocOffset++;
911 IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
912 Path.emplace_back(IDLocation, ModuleID);
913 auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
914
915 assert(CB && "Must have PPCallbacks after module loading");
916 CB->moduleImport(SourceLocation(), Path, ModResult);
917
918 if (!ModResult)
919 return false;
920
922 return false;
923
924 MDC->run(Consumer);
925 MDC->applyDiscoveredDependencies(ModuleInvocation);
926
927 bool Success = ModuleInvocation.withCowRef<bool>(
928 [&](CowCompilerInvocation &CowModuleInvocation) {
929 return Controller.finalize(CI, CowModuleInvocation);
930 });
931 if (!Success)
932 return false;
933
934 Consumer.handleBuildCommand(
935 {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
936
937 return true;
938 }
939
940 std::shared_ptr<ModuleDepCollector>
942 DependencyActionController &Controller) {
943 assert(CIPtr && "CIPtr must be initialized before calling this method");
944 auto &CI = *CIPtr;
945
946 std::optional<AsyncModuleCompiles> AsyncCompiles;
947 if (Worker.Service.getOpts().AsyncScanModules) {
948 AsyncCompiles.emplace();
949 if (!prescanModulesAsync(*AsyncCompiles, Controller))
950 return nullptr;
951 }
952
954 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
955 Worker.Service, *OriginalInvocation, Controller, PrebuiltModuleASTMap,
956 StableDirs);
957
959 return nullptr;
960
961 if (!Controller.initialize(CI, *OriginalInvocation))
962 return nullptr;
963
965 if (!CI.ExecuteAction(Action))
966 return nullptr;
967
968 MDC->run(Consumer);
969 if (!applyAndReport(*MDC, *OriginalInvocation, Consumer, Controller,
970 CommandLine[0]))
971 return nullptr;
972 return MDC;
973 }
974
976 CompilerInvocation &ModuleInvocation,
977 DependencyConsumer &Consumer,
978 DependencyActionController &Controller,
979 StringRef Executable) {
980 MDC.applyDiscoveredDependencies(ModuleInvocation);
981 bool Success = ModuleInvocation.withCowRef<bool>(
982 [&](CowCompilerInvocation &CowModuleInvocation) {
983 return Controller.finalize(*CIPtr, CowModuleInvocation);
984 });
985 if (!Success)
986 return false;
987 Consumer.handleBuildCommand(
988 {Executable.str(), ModuleInvocation.getCC1CommandLine()});
989 return true;
990 }
991};
992} // namespace dependencies
993} // namespace clang
994
997 : Service(Service) {
998 PCHContainerOps = std::make_shared<PCHContainerOperations>();
999 // We need to read object files from PCH built outside the scanner.
1000 PCHContainerOps->registerReader(
1001 std::make_unique<ObjectFilePCHContainerReader>());
1002 // The scanner itself writes only raw ast files.
1003 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
1004
1005 auto BaseFS = Service.getOpts().MakeVFS();
1006
1007 if (Service.getOpts().TraceVFS) {
1008 TracingFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(
1009 std::move(BaseFS));
1010 BaseFS = TracingFS;
1011 }
1012
1013 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
1014 Service, std::move(BaseFS));
1015}
1016
1018
1021 StringRef WorkingDirectory,
1024 if (OverlayFS) {
1025 auto NewFS =
1026 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(FS));
1027 NewFS->pushOverlay(std::move(OverlayFS));
1028 FS = std::move(NewFS);
1029 }
1030 FS->setCurrentWorkingDirectory(WorkingDirectory);
1031 return FS;
1032}
1033
1035 StringRef WorkingDirectory, ArrayRef<ArrayRef<std::string>> CommandLines,
1036 DependencyConsumer &DepConsumer, DependencyActionController &Controller,
1037 DiagnosticConsumer &DiagConsumer,
1039 auto FS = makeEffectiveVFS(WorkingDirectory, OverlayFS);
1040
1041 bool Scanned = false;
1042 std::shared_ptr<ModuleDepCollector> MDC;
1043 std::optional<CompilerInstanceWithContext> CIWC;
1044
1045 const bool Success = llvm::all_of(CommandLines, [&](const auto &Cmd) {
1046 if (StringRef(Cmd[1]) != "-cc1") {
1047 // Non-clang command. Just pass through to the dependency consumer.
1048 DepConsumer.handleBuildCommand(
1049 {Cmd.front(), {Cmd.begin() + 1, Cmd.end()}});
1050 return true;
1051 }
1052
1053 Service.getLogger().log().logArray("starting scanning command:", " ", Cmd);
1054 llvm::scope_exit ExitLogging([&] {
1055 Service.getLogger().log().logArray("finished scanning command:", " ",
1056 Cmd);
1057 });
1058
1059 auto DiagOpts = createScanningDiagOptions(Cmd);
1060 auto DiagEngine =
1061 CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DiagConsumer,
1062 /*ShouldOwnClient=*/false);
1063 if (!Scanned) {
1064 // Scanning runs once for the first -cc1 invocation in a chain of driver
1065 // jobs.
1066 // For any dependent jobs, reuse the scanning result and just update the
1067 // new invocation.
1068 // FIXME: to support multi-arch builds, each arch requires a separate
1069 // scan.
1070 Scanned = true;
1072 *this, WorkingDirectory, Cmd, *DiagEngine, OverlayFS, Controller);
1073 if (!Result)
1074 return false;
1075 CIWC.emplace(std::move(*Result));
1076 MDC = CIWC->scanTranslationUnit(DepConsumer, Controller);
1077 return MDC != nullptr;
1078 }
1079
1080 auto Invocation = createCompilerInvocation(Cmd, *DiagEngine);
1081 if (!Invocation)
1082 return false;
1083
1084 // The first cc1 is canonicalized in initializeScanInstance; each sibling
1085 // invocation must likewise be canonicalized before its cc1 command line is
1086 // emitted. This is mostly relevant for multi-arch jobs where we currently
1087 // do not do re-scans.
1088 if (any(Service.getOpts().OptimizeArgs & ScanningOptimizations::Macros))
1089 canonicalizeDefines(Invocation->getPreprocessorOpts());
1090
1091 assert(CIWC && "Must have an initialized CIWC");
1092 return CIWC->applyAndReport(*MDC, *Invocation, DepConsumer, Controller,
1093 Cmd.front());
1094 });
1095
1096 return Success && Scanned;
1097}
1098
1100 StringRef CWD, ArrayRef<std::string> CC1CommandLine,
1102 DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
1103 llvm::function_ref<std::optional<std::string>()> getNextName,
1104 DependencyConsumer &DepConsumer) {
1105 auto FS = makeEffectiveVFS(CWD, OverlayFS);
1106 auto DiagOpts = createScanningDiagOptions(CC1CommandLine);
1107 auto DiagEngine =
1108 CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DiagConsumer,
1109 /*ShouldOwnClient=*/false);
1110 std::optional<CompilerInstanceWithContext> CIWC =
1112 *this, CWD, CC1CommandLine, *DiagEngine, std::move(OverlayFS),
1113 Controller);
1114 if (!CIWC)
1115 return false;
1116
1117 bool AllScansSucceeded = true;
1118 while (std::optional<std::string> NextName = getNextName()) {
1119 bool Success =
1120 CIWC->computeDependencies(*NextName, DepConsumer, Controller);
1121 DepConsumer.finishQuery(*NextName, Success);
1122 AllScansSucceeded = AllScansSucceeded && Success;
1123 }
1124 return AllScansSucceeded;
1125}
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:1821
@ 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:1825
@ 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:1838
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:232
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasErrorOccurred() const
Definition Diagnostic.h:891
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition Diagnostic.h:699
DiagnosticConsumer * getClient()
Definition Diagnostic.h:623
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:645
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition Module.h:940
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 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.