clang 24.0.0git
DependencyScannerImpl.cpp
Go to the documentation of this file.
1//===- DependencyScannerImpl.cpp - Implements module dependency scanning --===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
18#include "llvm/ADT/IntrusiveRefCntPtr.h"
19#include "llvm/ADT/ScopeExit.h"
20#include "llvm/Option/Option.h"
21#include "llvm/Support/AdvisoryLock.h"
22#include "llvm/Support/CrashRecoveryContext.h"
23#include "llvm/Support/VirtualFileSystem.h"
24#include "llvm/TargetParser/Host.h"
25
26#include <mutex>
27#include <thread>
28
29using namespace clang;
30using namespace dependencies;
31
33 const HeaderSearchOptions &ExistingHSOpts,
34 DiagnosticsEngine *Diags,
35 const LangOptions &LangOpts) {
36 if (LangOpts.Modules) {
37 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
38 if (Diags) {
39 Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
40 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
41 if (VFSOverlays.empty()) {
42 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
43 } else {
44 std::string Files = llvm::join(VFSOverlays, "\n");
45 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
46 }
47 };
48 VFSNote(0, HSOpts.VFSOverlayFiles);
49 VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
50 }
51 }
52 }
53 return false;
54}
55
56namespace {
57
58using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
59
60/// A listener that collects the imported modules and the input
61/// files. While visiting, collect vfsoverlays and file inputs that determine
62/// whether prebuilt modules fully resolve in stable directories.
63class PrebuiltModuleListener : public ASTReaderListener {
64public:
65 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
66 llvm::SmallVector<std::string> &NewModuleFiles,
67 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
68 const HeaderSearchOptions &HSOpts,
69 const LangOptions &LangOpts, DiagnosticsEngine &Diags,
70 const ArrayRef<StringRef> StableDirs)
71 : PrebuiltModuleFiles(PrebuiltModuleFiles),
72 NewModuleFiles(NewModuleFiles),
73 PrebuiltModulesASTMap(PrebuiltModulesASTMap), ExistingHSOpts(HSOpts),
74 ExistingLangOpts(LangOpts), Diags(Diags), StableDirs(StableDirs) {}
75
76 bool needsImportVisitation() const override { return true; }
77 bool needsInputFileVisitation() override { return true; }
78 bool needsSystemInputFileVisitation() override { return true; }
79
80 /// Accumulate the modules are transitively depended on by the initial
81 /// prebuilt module.
82 void visitImport(StringRef ModuleName, StringRef Filename) override {
83 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
84 NewModuleFiles.push_back(Filename.str());
85
86 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(Filename);
87 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
88 if (PrebuiltMapEntry.second)
89 PrebuiltModule.setInStableDir(!StableDirs.empty());
90
91 if (auto It = PrebuiltModulesASTMap.find(CurrentFile);
92 It != PrebuiltModulesASTMap.end() && CurrentFile != Filename)
93 PrebuiltModule.addDependent(It->getKey());
94 }
95
96 /// For each input file discovered, check whether it's external path is in a
97 /// stable directory. Traversal is stopped if the current module is not
98 /// considered stable.
99 bool visitInputFileAsRequested(StringRef FilenameAsRequested,
100 StringRef Filename, bool isSystem,
101 bool isOverridden, time_t StoredTime,
102 bool isExplicitModule) override {
103 if (StableDirs.empty())
104 return false;
105 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
106 if ((PrebuiltEntryIt == PrebuiltModulesASTMap.end()) ||
107 (!PrebuiltEntryIt->second.isInStableDir()))
108 return false;
109
110 PrebuiltEntryIt->second.setInStableDir(
111 isPathInStableDir(StableDirs, Filename));
112 return PrebuiltEntryIt->second.isInStableDir();
113 }
114
115 /// Update which module that is being actively traversed.
116 void visitModuleFile(ModuleFileName Filename, serialization::ModuleKind Kind,
117 bool DirectlyImported) override {
118 // If the CurrentFile is not
119 // considered stable, update any of it's transitive dependents.
120 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
121 if ((PrebuiltEntryIt != PrebuiltModulesASTMap.end()) &&
122 !PrebuiltEntryIt->second.isInStableDir())
123 PrebuiltEntryIt->second.updateDependentsNotInStableDirs(
124 PrebuiltModulesASTMap);
125 CurrentFile = Filename.str();
126 }
127
128 /// Check the header search options for a given module when considering
129 /// if the module comes from stable directories.
130 bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
131 StringRef ModuleFilename, StringRef ContextHash,
132 bool Complain) override {
133
134 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
135 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
136 if (PrebuiltMapEntry.second)
137 PrebuiltModule.setInStableDir(!StableDirs.empty());
138
139 if (PrebuiltModule.isInStableDir())
140 PrebuiltModule.setInStableDir(areOptionsInStableDir(StableDirs, HSOpts));
141
142 return false;
143 }
144
145 /// Accumulate vfsoverlays used to build these prebuilt modules.
146 bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
147 bool Complain) override {
148
149 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
150 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
151 if (PrebuiltMapEntry.second)
152 PrebuiltModule.setInStableDir(!StableDirs.empty());
153
154 PrebuiltModule.setVFS(
155 llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles));
156
158 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
159 }
160
161private:
162 PrebuiltModuleFilesT &PrebuiltModuleFiles;
163 llvm::SmallVector<std::string> &NewModuleFiles;
164 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap;
165 const HeaderSearchOptions &ExistingHSOpts;
166 const LangOptions &ExistingLangOpts;
167 DiagnosticsEngine &Diags;
168 std::string CurrentFile;
169 const ArrayRef<StringRef> StableDirs;
170};
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} // namespace
274
276 using MacroOpt = std::pair<StringRef, std::size_t>;
277 std::vector<MacroOpt> SimpleNames;
278 SimpleNames.reserve(PPOpts.Macros.size());
279 std::size_t Index = 0;
280 for (const auto &M : PPOpts.Macros) {
281 auto SName = getSimpleMacroName(M.first);
282 // Skip optimizing if we can't guarantee we can preserve relative order.
283 if (!SName)
284 return;
285 SimpleNames.emplace_back(*SName, Index);
286 ++Index;
287 }
288
289 llvm::stable_sort(SimpleNames, llvm::less_first());
290 // Keep the last instance of each macro name by going in reverse
291 auto NewEnd = std::unique(
292 SimpleNames.rbegin(), SimpleNames.rend(),
293 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
294 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
295
296 // Apply permutation.
297 decltype(PPOpts.Macros) NewMacros;
298 NewMacros.reserve(SimpleNames.size());
299 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
300 std::size_t OriginalIndex = SimpleNames[I].second;
301 // We still emit undefines here as they may be undefining a predefined macro
302 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
303 }
304 std::swap(PPOpts.Macros, NewMacros);
305}
306
307namespace {
308class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
310
311public:
312 ScanningDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) {
313 FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) {
314 auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
315 if (DFS) {
316 assert(!DepFS && "Found multiple scanning VFSs");
317 DepFS = DFS;
318 }
319 });
320 assert(DepFS && "Did not find scanning VFS");
321 }
322
323 std::unique_ptr<DependencyDirectivesGetter>
324 cloneFor(FileManager &FileMgr) override {
325 return std::make_unique<ScanningDependencyDirectivesGetter>(FileMgr);
326 }
327
328 std::optional<ArrayRef<dependency_directives_scan::Directive>>
329 operator()(FileEntryRef File) override {
330 return DepFS->getDirectiveTokens(File.getName());
331 }
332};
333
334/// Sanitize diagnostic options for dependency scan.
335void 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} // namespace
355
356std::unique_ptr<DiagnosticOptions>
358 std::vector<const char *> CLI;
359 for (const std::string &Arg : CommandLine)
360 CLI.push_back(Arg.c_str());
361 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
362 sanitizeDiagOpts(*DiagOpts);
363 return DiagOpts;
364}
365
367 ArrayRef<std::string> CommandLine,
369 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
370 llvm::transform(CommandLine, CCommandLine.begin(),
371 [](const std::string &Str) { return Str.c_str(); });
372 DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
373 sanitizeDiagOpts(*DiagOpts);
375 /*ShouldOwnClient=*/false);
376}
377
378std::unique_ptr<CompilerInvocation>
380 DiagnosticsEngine &Diags) {
381 llvm::opt::ArgStringList Argv;
382 for (const std::string &Str : ArrayRef(CommandLine).drop_front())
383 Argv.push_back(Str.c_str());
384
385 auto Invocation = std::make_unique<CompilerInvocation>();
386 if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) {
387 // FIXME: Should we just go on like cc1_main does?
388 return nullptr;
389 }
390 return Invocation;
391}
392
394 CompilerInstance &ScanInstance,
396 DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
398 ScanInstance.setBuildingModule(false);
399 ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
400 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
401 if (!Service.getOpts().EmitWarnings)
402 ScanInstance.getDiagnostics().setIgnoreAllWarnings(true);
403 ScanInstance.createFileManager();
404 ScanInstance.createSourceManager();
405
406 // Use DepFS for getting the dependency directives if requested to do so.
409 std::make_unique<ScanningDependencyDirectivesGetter>(
410 ScanInstance.getFileManager()));
411}
412
413std::shared_ptr<CompilerInvocation> dependencies::createScanCompilerInvocation(
414 const CompilerInvocation &Invocation,
415 const DependencyScanningService &Service,
416 DependencyActionController &Controller) {
417 auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation);
418
419 sanitizeDiagOpts(ScanInvocation->getDiagnosticOpts());
420
421 ScanInvocation->getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
422 true;
423
424 if (ScanInvocation->getHeaderSearchOpts().ModulesValidateOncePerBuildSession)
425 ScanInvocation->getHeaderSearchOpts().BuildSessionTimestamp =
427
428 ScanInvocation->getFrontendOpts().DisableFree = false;
429 ScanInvocation->getFrontendOpts().GenerateGlobalModuleIndex = false;
430 ScanInvocation->getFrontendOpts().UseGlobalModuleIndex = false;
431 ScanInvocation->getFrontendOpts().GenReducedBMI = false;
432 ScanInvocation->getFrontendOpts().ModuleOutputPath.clear();
433 // This will prevent us compiling individual modules asynchronously since
434 // FileManager is not thread-safe, but it does improve performance for now.
435 ScanInvocation->getFrontendOpts().ModulesShareFileManager = true;
436 ScanInvocation->getHeaderSearchOpts().ModuleFormat = "raw";
437 ScanInvocation->getHeaderSearchOpts().ModulesIncludeVFSUsage =
439
440 // Consider different header search and diagnostic options to create
441 // different modules. This avoids the unsound aliasing of module PCMs.
442 //
443 // TODO: Implement diagnostic bucketing to reduce the impact of strict
444 // context hashing.
445 ScanInvocation->getHeaderSearchOpts().ModulesStrictContextHash = true;
446 ScanInvocation->getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
447 ScanInvocation->getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
448 ScanInvocation->getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
449 ScanInvocation->getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
450 true;
451 ScanInvocation->getHeaderSearchOpts().ModulesForceValidateUserHeaders = false;
452
453 // FIXME: Do this even with PCHs by marking the option as something like
454 // "preprocessor benign" in LangOptions.def so that it passes the
455 // compatibility checks in ASTReader.
456 if (ScanInvocation->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
457 // Application extension only affects the handling of availability
458 // attributes, which cannot change the dependencies.
459 ScanInvocation->getLangOpts().AppExt = false;
460 }
461
462 // Ensure that the scanner does not create new dependency collectors,
463 // and thus won't write out the extra '.d' files to disk.
464 ScanInvocation->getDependencyOutputOpts() = {};
465
466 Controller.initializeScanInvocation(*ScanInvocation);
467
468 return ScanInvocation;
469}
470
473 // Create a collection of stable directories derived from the ScanInstance
474 // for determining whether module dependencies would fully resolve from
475 // those directories.
477 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
478 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
479 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
480 return StableDirs;
481}
482
483std::optional<PrebuiltModulesAttrsMap>
485 CompilerInstance &ScanInstance, llvm::SmallVector<StringRef> &StableDirs) {
486 // Store a mapping of prebuilt module files and their properties like header
487 // search options. This will prevent the implicit build to create duplicate
488 // modules and will force reuse of the existing prebuilt module files
489 // instead.
490 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
491
492 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
493 if (visitPrebuiltModule(
494 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance,
496 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
497 return {};
498
499 return PrebuiltModulesASTMap;
500}
501
502std::unique_ptr<DependencyOutputOptions>
504 const CompilerInvocation &Invocation) {
505 auto Opts = std::make_unique<DependencyOutputOptions>(
506 Invocation.getDependencyOutputOpts());
507 // We need at least one -MT equivalent for the generator of make dependency
508 // files to work.
509 if (Opts->Targets.empty())
510 Opts->Targets = {deduceDepTarget(Invocation.getFrontendOpts().OutputFile,
511 Invocation.getFrontendOpts().Inputs)};
512 Opts->IncludeSystemHeaders = true;
513
514 return Opts;
515}
516
517std::shared_ptr<ModuleDepCollector>
519 CompilerInstance &ScanInstance,
520 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
522 DependencyActionController &Controller,
523 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
524 SmallVector<StringRef> &StableDirs) {
525 auto MDC = std::make_shared<ModuleDepCollector>(
526 Service, std::move(DepOutputOpts), ScanInstance, Controller, Inv,
527 std::move(PrebuiltModulesASTMap), StableDirs);
528 ScanInstance.addDependencyCollector(MDC);
529 return MDC;
530}
531
532/// Manages (and terminates) the asynchronous compilation of modules.
534 std::mutex Mutex;
535 bool Stop = false;
536 // FIXME: Have the service own a thread pool and use that instead.
537 std::vector<std::thread> Compiles;
538
539public:
540 /// Registers the module compilation, unless this instance is about to be
541 /// destroyed.
542 void add(llvm::unique_function<void()> Compile) {
543 std::lock_guard<std::mutex> Lock(Mutex);
544 if (!Stop)
545 Compiles.emplace_back(std::move(Compile));
546 }
547
549 {
550 // Prevent registration of further module compiles.
551 std::lock_guard<std::mutex> Lock(Mutex);
552 Stop = true;
553 }
554
555 // Wait for outstanding module compiles to finish.
556 for (std::thread &Compile : Compiles)
557 Compile.join();
558 }
559};
560
573
574/// The preprocessor callback that takes care of initiating an asynchronous
575/// module compilation if needed.
581
586
587 void moduleLoadSkipped(Module *M) override {
588 M = M->getTopLevelModule();
589
590 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
591 ModuleCache &ModCache = CI.getModuleCache();
593
594 uint64_t Timestamp = ModCache.getModuleTimestamp(ModuleFileName);
595 // Someone else already built/validated the PCM.
596 if (Timestamp > CI.getHeaderSearchOpts().BuildSessionTimestamp)
597 return;
598
599 if (!CI.getASTReader())
600 CI.createASTReader();
602 // Only calling ReadASTCore() to avoid the expensive eager deserialization
603 // of the clang::Module objects in ReadAST().
604 // FIXME: Consider doing this in the new thread depending on how expensive
605 // the read turns out to be.
606 switch (CI.getASTReader()->ReadASTCore(
608 nullptr, Imported, {}, {}, {},
612 // We successfully read a valid, up-to-date PCM.
613 // FIXME: This could update the timestamp. Regular calls to
614 // ASTReader::ReadAST() would do so unless they encountered corrupted
615 // AST block, corrupted extension block, or did not read the expected
616 // top-level module.
617 return;
620 // The most interesting case.
621 break;
622 default:
623 // Let the regular scan diagnose this.
624 return;
625 }
626
627 auto Lock = ModCache.getLock(ModuleFileName);
628 bool Owned;
629 llvm::Error LockErr = Lock->tryLock().moveInto(Owned);
630 // Someone else is building the PCM right now.
631 if (!LockErr && !Owned)
632 return;
633 // We should build the PCM.
635 llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
636 Service, Service.getOpts().MakeVFS());
637 VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
638 CI.getDiagnostics(), std::move(VFS));
639 auto DC = std::make_unique<DiagnosticConsumer>();
640 auto MC = makeInProcessModuleCache(Service.getModuleCacheEntries(),
641 Service.getLogger());
642 CompilerInstance::ThreadSafeCloneConfig CloneConfig(std::move(VFS), *DC,
643 std::move(MC));
644 auto ModCI1 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
645 CloneConfig);
646 auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
647 CloneConfig);
648
649 auto ModController = Controller.clone();
650
651 // Note: This lock belongs to a module cache that might not outlive the
652 // thread. This works, because the in-process lock only refers to an object
653 // managed by the service, which does outlive the thread.
654 Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
655 ModCI2 = std::move(ModCI2), DC = std::move(DC),
656 ModController = std::move(ModController), Service = &Service,
657 Compiles = &Compiles] {
658 llvm::CrashRecoveryContext CRC;
659 (void)CRC.RunSafely([&] {
660 // Quickly discovers and compiles modules for the real scan below.
661 SingleModuleWithAsyncModuleCompiles Action1(*Service, *ModController,
662 *Compiles);
663 (void)ModCI1->ExecuteAction(Action1);
664 // The real scan below.
665 ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
666 GenerateModuleFromModuleMapAction Action2;
667 (void)ModCI2->ExecuteAction(Action2);
668 });
669 });
670 }
671};
672
673/// Runs the preprocessor on a TU with single-module-parse-mode and compiles
674/// modules asynchronously without blocking or importing them.
692
694 CompilerInstance &CI) {
697 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
698 return true;
699}
700
702 std::string Executable,
703 std::unique_ptr<CompilerInvocation> OriginalInvocation,
705 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
706 DiagnosticConsumer *DiagConsumer) {
707 // Making sure that we canonicalize the defines early to avoid unnecessary
708 // variants in both the scanner and in the resulting explicit command lines.
709 if (any(Service.getOpts().OptimizeArgs & ScanningOptimizations::Macros))
710 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
711
712 if (Scanned) {
713 CompilerInstance &ScanInstance = *ScanInstanceStorage;
714
715 // Scanning runs once for the first -cc1 invocation in a chain of driver
716 // jobs. For any dependent jobs, reuse the scanning result and just
717 // update the new invocation.
718 // FIXME: to support multi-arch builds, each arch requires a separate scan
719 if (MDC)
720 MDC->applyDiscoveredDependencies(*OriginalInvocation);
721
722 bool Success = OriginalInvocation->withCowRef<bool>(
723 [&](CowCompilerInvocation &CowOriginalInvocation) {
724 return Controller.finalize(ScanInstance, CowOriginalInvocation);
725 });
726 if (!Success)
727 return false;
728
729 Consumer.handleBuildCommand(
730 {Executable, OriginalInvocation->getCC1CommandLine()});
731 return true;
732 }
733
734 Scanned = true;
735
736 // Create a compiler instance to handle the actual work.
737 auto ScanInvocation =
738 createScanCompilerInvocation(*OriginalInvocation, Service, Controller);
739
740 // Quickly discovers and compiles modules for the real scan below.
741 std::optional<AsyncModuleCompiles> AsyncCompiles;
742 if (Service.getOpts().AsyncScanModules) {
743 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries(),
744 Service.getLogger());
745 auto ScanInstanceStorage = std::make_unique<CompilerInstance>(
746 std::make_shared<CompilerInvocation>(*ScanInvocation), PCHContainerOps,
747 std::move(ModCache));
748 CompilerInstance &ScanInstance = *ScanInstanceStorage;
749
750 DiagnosticConsumer DiagConsumer;
751 initializeScanCompilerInstance(ScanInstance, FS, &DiagConsumer, Service,
752 DepFS);
753
754 // FIXME: Do this only once.
755 SmallVector<StringRef> StableDirs = getInitialStableDirs(ScanInstance);
756 auto MaybePrebuiltModulesASTMap =
757 computePrebuiltModulesASTMap(ScanInstance, StableDirs);
758 if (!MaybePrebuiltModulesASTMap)
759 return false;
760
761 // Normally this would be handled by GeneratePCHAction
763 ScanInstance.getLangOpts().CompilingPCH = true;
764
765 AsyncCompiles.emplace();
766 SingleTUWithAsyncModuleCompiles Action(Service, Controller, *AsyncCompiles);
767 (void)ScanInstance.ExecuteAction(Action);
768 }
769
770 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries(),
771 Service.getLogger());
772 ScanInstanceStorage.emplace(std::move(ScanInvocation),
773 std::move(PCHContainerOps), std::move(ModCache));
774 CompilerInstance &ScanInstance = *ScanInstanceStorage;
775
776 initializeScanCompilerInstance(ScanInstance, FS, DiagConsumer, Service,
777 DepFS);
778
779 llvm::SmallVector<StringRef> StableDirs = getInitialStableDirs(ScanInstance);
780 auto MaybePrebuiltModulesASTMap =
781 computePrebuiltModulesASTMap(ScanInstance, StableDirs);
782 if (!MaybePrebuiltModulesASTMap)
783 return false;
784
785 auto DepOutputOpts = createDependencyOutputOptions(*OriginalInvocation);
786
788 ScanInstance, std::move(DepOutputOpts), Service, *OriginalInvocation,
789 Controller, *MaybePrebuiltModulesASTMap, StableDirs);
790
791 if (ScanInstance.getDiagnostics().hasErrorOccurred())
792 return false;
793
794 if (!Controller.initialize(ScanInstance, *OriginalInvocation))
795 return false;
796
798 const bool Result = ScanInstance.ExecuteAction(Action);
799
800 if (Result) {
801 if (MDC) {
802 MDC->run(Consumer);
803 MDC->applyDiscoveredDependencies(*OriginalInvocation);
804 }
805
806 bool Success = OriginalInvocation->withCowRef<bool>(
807 [&](CowCompilerInvocation &CowOriginalInvocation) {
808 return Controller.finalize(ScanInstance, CowOriginalInvocation);
809 });
810 if (!Success)
811 return false;
812
813 Consumer.handleBuildCommand(
814 {Executable, OriginalInvocation->getCC1CommandLine()});
815 }
816
817 return Result;
818}
static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts, const HeaderSearchOptions &ExistingHSOpts, DiagnosticsEngine *Diags, const LangOptions &LangOpts)
Manages (and terminates) the asynchronous compilation of modules.
void add(llvm::unique_function< void()> Compile)
Registers the module compilation, unless this instance is about to be destroyed.
Abstract interface for callback invocations by the ASTReader.
Definition ASTReader.h:117
@ ARR_Missing
The client can handle an AST file that cannot load because it is missing.
Definition ASTReader.h:1825
@ 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:1829
@ 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:1842
static bool readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, const ModuleCache &ModCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities=ARR_ConfigurationMismatch|ARR_OutOfDate)
Read the control block for the named AST file.
@ Success
The control block was read successfully.
Definition ASTReader.h:450
@ OutOfDate
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition ASTReader.h:460
@ Missing
The AST file was missing.
Definition ASTReader.h:456
Configuration object for making the result of cloneForModuleCompile() thread-safe.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
void createFileManager()
Create the file manager and replace any existing one with it.
FileManager & getFileManager() const
Return the current file manager to the caller.
ModuleCache & getModuleCache() const
void addDependencyCollector(std::shared_ptr< DependencyCollector > Listener)
Preprocessor & getPreprocessor() const
Return the current preprocessor.
void createVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS=llvm::vfs::getRealFileSystem(), DiagnosticConsumer *DC=nullptr)
Create a virtual file system instance based on the invocation.
FrontendOptions & getFrontendOpts()
HeaderSearchOptions & getHeaderSearchOpts()
void createSourceManager()
Create the source manager and replace any existing one with it.
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
void setDependencyDirectivesGetter(std::unique_ptr< DependencyDirectivesGetter > Getter)
Helper class for holding the data necessary to invoke the compiler.
PreprocessorOptions & getPreprocessorOpts()
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
DependencyOutputOptions & getDependencyOutputOpts()
FrontendOptions & getFrontendOpts()
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:882
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition Diagnostic.h:690
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:52
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.).
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
ModuleFileName getCachedModuleFileName(Module *Module)
Retrieve the name of the cached module file that should be used to load the given module.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
The module cache used for compiling modules implicitly.
Definition ModuleCache.h:39
virtual std::time_t getModuleTimestamp(StringRef ModuleFilename)=0
Returns the timestamp denoting the last time inputs of the module file were validated.
virtual std::unique_ptr< llvm::AdvisoryLock > getLock(StringRef ModuleFilename)=0
Returns lock for the given module file. The lock is initially unlocked.
Identifies a module file to be loaded.
Definition Module.h:109
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.
Describes a module or submodule.
Definition Module.h:340
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
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool SingleModuleParseMode
When enabled, preprocessor is in a mode for parsing a single module only.
std::vector< std::pair< std::string, bool > > Macros
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Preprocessor-based frontend action that also loads PCH files.
Encodes a location in the source.
The base class of the type hierarchy.
Definition TypeBase.h:1875
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
virtual void initializeScanInvocation(CompilerInvocation &ScanInvocation)
Initializes the scan invocation.
bool runInvocation(std::string Executable, std::unique_ptr< CompilerInvocation > Invocation, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer)
The dependency scanning service contains shared configuration and state that is used by the individua...
const DependencyScanningServiceOptions & getOpts() const
A virtual file system optimized for the dependency discovery.
void setVFS(llvm::StringSet<> &&VFS)
Update the VFSMap to the one discovered from serializing the AST file.
bool isInStableDir() const
Read-only access to whether the module is made up of dependencies in stable directories.
void addDependent(StringRef ModuleFile)
Add a direct dependent module file, so it can be updated if the current module is from stable directo...
void setInStableDir(bool V=false)
Update whether the prebuilt module resolves entirely in a stable directories.
SmallVector< StringRef > getInitialStableDirs(const CompilerInstance &ScanInstance)
bool areOptionsInStableDir(const ArrayRef< StringRef > Directories, const HeaderSearchOptions &HSOpts)
Determine if options collected from a module's compilation can safely be considered as stable.
@ VFS
Remove unused -ivfsoverlay arguments.
std::shared_ptr< CompilerInvocation > createScanCompilerInvocation(const CompilerInvocation &Invocation, const DependencyScanningService &Service, DependencyActionController &Controller)
Creates a CompilerInvocation suitable for the dependency scanner.
void initializeScanCompilerInstance(CompilerInstance &ScanInstance, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, IntrusiveRefCntPtr< DependencyScanningWorkerFilesystem > DepFS)
llvm::StringMap< PrebuiltModuleASTAttrs > PrebuiltModulesAttrsMap
Attributes loaded from AST files of prebuilt modules collected prior to ModuleDepCollector creation.
std::unique_ptr< CompilerInvocation > createCompilerInvocation(ArrayRef< std::string > CommandLine, DiagnosticsEngine &Diags)
void canonicalizeDefines(PreprocessorOptions &PPOpts)
Canonicalizes command-line macro defines (e.g. removing "-DX -UX").
std::unique_ptr< DependencyOutputOptions > createDependencyOutputOptions(const CompilerInvocation &Invocation)
Creates dependency output options to be reported to the dependency consumer, deducing missing informa...
std::optional< PrebuiltModulesAttrsMap > computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, SmallVector< StringRef > &StableDirs)
std::unique_ptr< DiagnosticOptions > createDiagOptions(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.
std::shared_ptr< ModuleDepCollector > initializeScanInstanceDependencyCollector(CompilerInstance &ScanInstance, std::unique_ptr< DependencyOutputOptions > DepOutputOpts, DependencyScanningService &Service, CompilerInvocation &Inv, DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, SmallVector< StringRef > &StableDirs)
Create the dependency collector that will collect the produced dependencies.
@ DependencyDirectivesScan
This mode is used to compute the dependencies by running the preprocessor with special kind of lexing...
@ GeneratePCH
Generate pre-compiled header.
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h: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
The JSON file list parser is used to communicate input to InstallAPI.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
Definition Parser.h:65
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Result
The result type of a method or function.
Definition TypeBase.h:905
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
DependencyActionController & Controller
AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
void moduleLoadSkipped(Module *M) override
Callback invoked whenever a module load was skipped due to enabled single-module-parse-mode.
AsyncModuleCompiles & Compiles
DependencyScanningService & Service
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
Runs the preprocessor on a TU with single-module-parse-mode and compiles modules asynchronously witho...
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service, DependencyActionController &Controller, AsyncModuleCompiles &Compiles)
DependencyScanningService & Service
DependencyActionController & Controller
ScanningMode Mode
Whether to use optimized dependency directive scan or full preprocessing.
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.
IntrusiveRefCntPtr< DiagnosticsEngine > DiagEngine
DiagnosticsEngineWithDiagOpts(ArrayRef< std::string > CommandLine, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, DiagnosticConsumer &DC)