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