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
21#include "llvm/ADT/IntrusiveRefCntPtr.h"
22#include "llvm/ADT/ScopeExit.h"
23#include "llvm/Option/Option.h"
24#include "llvm/Support/AdvisoryLock.h"
25#include "llvm/Support/CrashRecoveryContext.h"
26#include "llvm/Support/VirtualFileSystem.h"
27#include "llvm/TargetParser/Host.h"
28#include <mutex>
29#include <thread>
30
31using namespace clang;
32using namespace dependencies;
33
35 const HeaderSearchOptions &ExistingHSOpts,
36 DiagnosticsEngine *Diags,
37 const LangOptions &LangOpts) {
38 if (LangOpts.Modules) {
39 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
40 if (Diags) {
41 Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
42 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
43 if (VFSOverlays.empty()) {
44 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
45 } else {
46 std::string Files = llvm::join(VFSOverlays, "\n");
47 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
48 }
49 };
50 VFSNote(0, HSOpts.VFSOverlayFiles);
51 VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
52 }
53 }
54 }
55 return false;
56}
57namespace {
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} // namespace
172
173/// Visit the given prebuilt module and collect all of the modules it
174/// transitively imports and contributing input files.
175static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
177 PrebuiltModuleFilesT &ModuleFiles,
178 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
179 DiagnosticsEngine &Diags,
180 const ArrayRef<StringRef> StableDirs) {
181 // List of module files to be processed.
183
184 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModulesASTMap,
186 Diags, StableDirs);
187
188 Listener.visitModuleFile(ModuleFileName::makeExplicit(PrebuiltModuleFilename),
190 /*DirectlyImported=*/true);
192 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
194 /*FindModuleFileExtensions=*/false, Listener,
195 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
196 return true;
197
198 while (!Worklist.empty()) {
199 // FIXME: This is assuming the PCH only refers to explicitly-built modules,
200 // which technically is not guaranteed. To remove the assumption, we'd need
201 // to also rework how the module files are handled to the scan, specifically
202 // change the values of HeaderSearchOptions::PrebuiltModuleFiles from plain
203 // paths to ModuleFileName.
204 Listener.visitModuleFile(ModuleFileName::makeExplicit(Worklist.back()),
206 /*DirectlyImported=*/false);
208 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
210 /*FindModuleFileExtensions=*/false, Listener,
211 /*ValidateDiagnosticOptions=*/false))
212 return true;
213 }
214 return false;
215}
216
217/// Transform arbitrary file name into an object-like file name.
218static std::string makeObjFileName(StringRef FileName) {
219 SmallString<128> ObjFileName(FileName);
220 llvm::sys::path::replace_extension(ObjFileName, "o");
221 return std::string(ObjFileName);
222}
223
224/// Deduce the dependency target based on the output file and input files.
225static std::string
226deduceDepTarget(const std::string &OutputFile,
227 const SmallVectorImpl<FrontendInputFile> &InputFiles) {
228 if (OutputFile != "-")
229 return OutputFile;
230
231 if (InputFiles.empty() || !InputFiles.front().isFile())
232 return "clang-scan-deps\\ dependency";
233
234 return makeObjFileName(InputFiles.front().getFile());
235}
236
237// Clang implements -D and -U by splatting text into a predefines buffer. This
238// allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
239// define the same macro, or adding C++ style comments before the macro name.
240//
241// This function checks that the first non-space characters in the macro
242// obviously form an identifier that can be uniqued on without lexing. Failing
243// to do this could lead to changing the final definition of a macro.
244//
245// We could set up a preprocessor and actually lex the name, but that's very
246// heavyweight for a situation that will almost never happen in practice.
247static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
248 StringRef Name = Macro.split("=").first.ltrim(" \t");
249 std::size_t I = 0;
250
251 auto FinishName = [&]() -> std::optional<StringRef> {
252 StringRef SimpleName = Name.slice(0, I);
253 if (SimpleName.empty())
254 return std::nullopt;
255 return SimpleName;
256 };
257
258 for (; I != Name.size(); ++I) {
259 switch (Name[I]) {
260 case '(': // Start of macro parameter list
261 case ' ': // End of macro name
262 case '\t':
263 return FinishName();
264 case '_':
265 continue;
266 default:
267 if (llvm::isAlnum(Name[I]))
268 continue;
269 return std::nullopt;
270 }
271 }
272 return FinishName();
273}
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 {
309 DependencyScanningWorkerFilesystem *DepFS;
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} // namespace
334
335/// Sanitize diagnostic options for dependency scan.
336static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
337 // Don't print 'X warnings and Y errors generated'.
338 DiagOpts.ShowCarets = false;
339 // Don't write out diagnostic file.
340 DiagOpts.DiagnosticSerializationFile.clear();
341 // Don't emit warnings except for scanning specific warnings.
342 // TODO: It would be useful to add a more principled way to ignore all
343 // warnings that come from source code. The issue is that we need to
344 // ignore warnings that could be surpressed by
345 // `#pragma clang diagnostic`, while still allowing some scanning
346 // warnings for things we're not ready to turn into errors yet.
347 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
348 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
349 return llvm::StringSwitch<bool>(Warning)
350 .Cases({"pch-vfs-diff", "error=pch-vfs-diff"}, false)
351 .StartsWith("no-error=", false)
352 .Default(true);
353 });
354}
355
356static std::unique_ptr<CompilerInvocation>
358 DiagnosticsEngine &Diags) {
359 llvm::opt::ArgStringList Argv;
360 for (const std::string &Str : ArrayRef(CommandLine).drop_front())
361 Argv.push_back(Str.c_str());
362
363 auto Invocation = std::make_unique<CompilerInvocation>();
364 if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) {
365 // FIXME: Should we just go on like cc1_main does?
366 return nullptr;
367 }
368 return Invocation;
369}
370
372 CompilerInstance &ScanInstance,
374 DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
376 ScanInstance.setBuildingModule(false);
377 ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
378 ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
379 if (!Service.getOpts().EmitWarnings)
380 ScanInstance.getDiagnostics().setIgnoreAllWarnings(true);
381 ScanInstance.createFileManager();
382 ScanInstance.createSourceManager();
383
384 // Use DepFS for getting the dependency directives if requested to do so.
385 if (Service.getOpts().Mode == ScanningMode::DependencyDirectivesScan)
387 std::make_unique<ScanningDependencyDirectivesGetter>(
388 ScanInstance.getFileManager()));
389}
390
391static std::shared_ptr<CompilerInvocation>
393 const DependencyScanningService &Service,
394 DependencyActionController &Controller) {
395 auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation);
396
397 sanitizeDiagOpts(ScanInvocation->getDiagnosticOpts());
398
399 ScanInvocation->getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
400 true;
401
402 if (ScanInvocation->getHeaderSearchOpts()
403 .ModulesValidateOncePerBuildSession ||
405 ScanInvocation->getHeaderSearchOpts().BuildSessionTimestamp =
408 ScanInvocation->getHeaderSearchOpts().ModulesValidateDirectoryDependencies =
409 true;
410
411 ScanInvocation->getFrontendOpts().DisableFree = false;
412 ScanInvocation->getFrontendOpts().GenerateGlobalModuleIndex = false;
413 ScanInvocation->getFrontendOpts().UseGlobalModuleIndex = false;
414 ScanInvocation->getFrontendOpts().GenReducedBMI = false;
415 ScanInvocation->getFrontendOpts().ModuleOutputPath.clear();
416 // This will prevent us compiling individual modules asynchronously since
417 // FileManager is not thread-safe, but it does improve performance for now.
418 ScanInvocation->getFrontendOpts().ModulesShareFileManager = true;
419 ScanInvocation->getHeaderSearchOpts().ModuleFormat = "raw";
420 ScanInvocation->getHeaderSearchOpts().ModulesIncludeVFSUsage =
421 any(Service.getOpts().OptimizeArgs & ScanningOptimizations::VFS);
422
423 // Consider different header search and diagnostic options to create
424 // different modules. This avoids the unsound aliasing of module PCMs.
425 //
426 // TODO: Implement diagnostic bucketing to reduce the impact of strict
427 // context hashing.
428 ScanInvocation->getHeaderSearchOpts().ModulesStrictContextHash = true;
429 ScanInvocation->getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
430 ScanInvocation->getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
431 ScanInvocation->getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
432 ScanInvocation->getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings =
433 true;
434 ScanInvocation->getHeaderSearchOpts().ModulesForceValidateUserHeaders = false;
435
436 // FIXME: Do this even with PCHs by marking the option as something like
437 // "preprocessor benign" in LangOptions.def so that it passes the
438 // compatibility checks in ASTReader.
439 if (ScanInvocation->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
440 // Application extension only affects the handling of availability
441 // attributes, which cannot change the dependencies.
442 ScanInvocation->getLangOpts().AppExt = false;
443 }
444
445 // Ensure that the scanner does not create new dependency collectors,
446 // and thus won't write out the extra '.d' files to disk.
447 ScanInvocation->getDependencyOutputOpts() = {};
448
449 Controller.initializeScanInvocation(*ScanInvocation);
450
451 return ScanInvocation;
452}
453
456 // Create a collection of stable directories derived from the ScanInstance
457 // for determining whether module dependencies would fully resolve from
458 // those directories.
460 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
461 if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != Sysroot))
462 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
463 return StableDirs;
464}
465
466static std::optional<PrebuiltModulesAttrsMap>
468 llvm::SmallVector<StringRef> &StableDirs) {
469 // Store a mapping of prebuilt module files and their properties like header
470 // search options. This will prevent the implicit build to create duplicate
471 // modules and will force reuse of the existing prebuilt module files
472 // instead.
473 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
474
475 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
477 ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance,
479 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
480 return {};
481
482 return PrebuiltModulesASTMap;
483}
484
485static std::unique_ptr<DependencyOutputOptions>
487 auto Opts = std::make_unique<DependencyOutputOptions>(
488 Invocation.getDependencyOutputOpts());
489 // We need at least one -MT equivalent for the generator of make dependency
490 // files to work.
491 if (Opts->Targets.empty())
492 Opts->Targets = {deduceDepTarget(Invocation.getFrontendOpts().OutputFile,
493 Invocation.getFrontendOpts().Inputs)};
494 Opts->IncludeSystemHeaders = true;
495
496 return Opts;
497}
498
499static std::shared_ptr<ModuleDepCollector>
501 CompilerInstance &ScanInstance,
502 std::unique_ptr<DependencyOutputOptions> DepOutputOpts,
504 DependencyActionController &Controller,
505 PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
506 SmallVector<StringRef> &StableDirs) {
507 auto MDC = std::make_shared<ModuleDepCollector>(
508 Service, std::move(DepOutputOpts), ScanInstance, Controller, Inv,
509 std::move(PrebuiltModulesASTMap), StableDirs);
510 ScanInstance.addDependencyCollector(MDC);
511 return MDC;
512}
513
514namespace {
515/// Manages (and terminates) the asynchronous compilation of modules.
516class AsyncModuleCompiles {
517 std::mutex Mutex;
518 bool Stop = false;
519 // FIXME: Have the service own a thread pool and use that instead.
520 std::vector<std::thread> Compiles;
521
522public:
523 /// Registers the module compilation, unless this instance is about to be
524 /// destroyed.
525 void add(llvm::unique_function<void()> Compile) {
526 std::lock_guard<std::mutex> Lock(Mutex);
527 if (!Stop)
528 Compiles.emplace_back(std::move(Compile));
529 }
530
531 ~AsyncModuleCompiles() {
532 {
533 std::lock_guard<std::mutex> Lock(Mutex);
534 Stop = true;
535 }
536 for (std::thread &Compile : Compiles)
537 Compile.join();
538 }
539};
540
541struct SingleModuleWithAsyncModuleCompiles : PreprocessOnlyAction {
542 DependencyScanningService &Service;
543 DependencyActionController &Controller;
544 AsyncModuleCompiles &Compiles;
545
546 SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service,
547 DependencyActionController &Controller,
548 AsyncModuleCompiles &Compiles)
549 : Service(Service), Controller(Controller), Compiles(Compiles) {}
550
551 bool BeginSourceFileAction(CompilerInstance &CI) override;
552};
553
554/// Runs the preprocessor on a TU with single-module-parse-mode and compiles
555/// modules asynchronously without blocking or importing them.
556struct SingleTUWithAsyncModuleCompiles : PreprocessOnlyAction {
557 DependencyScanningService &Service;
558 DependencyActionController &Controller;
559 AsyncModuleCompiles &Compiles;
560
561 SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service,
562 DependencyActionController &Controller,
563 AsyncModuleCompiles &Compiles)
564 : Service(Service), Controller(Controller), Compiles(Compiles) {}
565
566 bool BeginSourceFileAction(CompilerInstance &CI) override;
567};
568
569/// The preprocessor callback that takes care of initiating an asynchronous
570/// module compilation if needed.
571struct AsyncModuleCompile : PPCallbacks {
572 CompilerInstance &CI;
573 DependencyScanningService &Service;
574 DependencyActionController &Controller;
575 AsyncModuleCompiles &Compiles;
576
577 AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service,
578 DependencyActionController &Controller,
579 AsyncModuleCompiles &Compiles)
580 : CI(CI), Service(Service), Controller(Controller), Compiles(Compiles) {}
581
582 void moduleLoadSkipped(Module *M) override {
583 M = M->getTopLevelModule();
584
585 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
586 ModuleCache &ModCache = CI.getModuleCache();
587 ModuleFileName ModuleFileName = HS.getCachedModuleFileName(M);
588
589 uint64_t Timestamp = ModCache.getModuleTimestamp(ModuleFileName);
590 // Someone else already built/validated the PCM.
591 if (Timestamp > CI.getHeaderSearchOpts().BuildSessionTimestamp)
592 return;
593
594 if (!CI.getASTReader())
595 CI.createASTReader();
596 SmallVector<ASTReader::ImportedModule, 0> Imported;
597 // Only calling ReadASTCore() to avoid the expensive eager deserialization
598 // of the clang::Module objects in ReadAST().
599 // FIXME: Consider doing this in the new thread depending on how expensive
600 // the read turns out to be.
601 switch (CI.getASTReader()->ReadASTCore(
602 ModuleFileName, serialization::MK_ImplicitModule, SourceLocation(),
603 nullptr, Imported, {}, {}, {},
607 // We successfully read a valid, up-to-date PCM.
608 // FIXME: This could update the timestamp. Regular calls to
609 // ASTReader::ReadAST() would do so unless they encountered corrupted
610 // AST block, corrupted extension block, or did not read the expected
611 // top-level module.
612 return;
615 // The most interesting case.
616 break;
617 default:
618 // Let the regular scan diagnose this.
619 return;
620 }
621
622 auto Lock = ModCache.getLock(ModuleFileName);
623 bool Owned;
624 llvm::Error LockErr = Lock->tryLock().moveInto(Owned);
625 // Someone else is building the PCM right now.
626 if (!LockErr && !Owned)
627 return;
628 // We should build the PCM.
629 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
630 llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
631 Service, Service.getOpts().MakeVFS());
632 VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
633 CI.getDiagnostics(), std::move(VFS));
634 auto DC = std::make_unique<DiagnosticConsumer>();
635 auto MC = makeInProcessModuleCache(Service.getModuleCacheEntries(),
636 Service.getLogger());
637 CompilerInstance::ThreadSafeCloneConfig CloneConfig(std::move(VFS), *DC,
638 std::move(MC));
639 auto ModCI1 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
640 CloneConfig);
641 auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
642 CloneConfig);
643
644 auto ModController = Controller.clone();
645
646 // Note: This lock belongs to a module cache that might not outlive the
647 // thread. This works, because the in-process lock only refers to an object
648 // managed by the service, which does outlive the thread.
649 Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
650 ModCI2 = std::move(ModCI2), DC = std::move(DC),
651 ModController = std::move(ModController), Service = &Service,
652 Compiles = &Compiles] {
653 llvm::CrashRecoveryContext CRC;
654 (void)CRC.RunSafely([&] {
655 // Quickly discovers and compiles modules for the real scan below.
656 SingleModuleWithAsyncModuleCompiles Action1(*Service, *ModController,
657 *Compiles);
658 (void)ModCI1->ExecuteAction(Action1);
659 // The real scan below.
660 ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
661 GenerateModuleFromModuleMapAction Action2;
662 (void)ModCI2->ExecuteAction(Action2);
663 });
664 });
665 }
666};
667
668bool SingleModuleWithAsyncModuleCompiles::BeginSourceFileAction(
669 CompilerInstance &CI) {
672 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
673 return true;
674}
675
676bool SingleTUWithAsyncModuleCompiles::BeginSourceFileAction(
677 CompilerInstance &CI) {
680 std::make_unique<AsyncModuleCompile>(CI, Service, Controller, Compiles));
681 return true;
682}
683} // namespace
684
687 DependencyActionController &Controller,
688 AsyncModuleCompiles &Compiles) {
689 SingleTUWithAsyncModuleCompiles Action(Service, Controller, Compiles);
690 (void)PrescanCI.ExecuteAction(Action);
691}
692
693namespace clang {
694namespace dependencies {
695
696std::unique_ptr<DiagnosticOptions>
698 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
699 llvm::transform(CommandLine, CCommandLine.begin(),
700 [](const std::string &Str) { return Str.c_str(); });
701 auto DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
702 sanitizeDiagOpts(*DiagOpts);
703 return DiagOpts;
704}
705
706namespace {
707/// Find the module maps that define modules without loading them.
708class ModuleMapLookup {
709public:
710 explicit ModuleMapLookup(CompilerInstance &CI)
711 : CI(CI), HSOpts(CI.getHeaderSearchOpts()),
712 Diags(DiagnosticIDs::create(), DiagOpts, new IgnoringDiagConsumer()),
713 SourceMgr(Diags, CI.getFileManager()),
714 HS(HSOpts, SourceMgr, Diags, CI.getLangOpts(), &CI.getTarget()) {
715 HSOpts.LazyLoadModuleMaps = true;
716 // Ignore verbose mode as it's already respected by the real scan.
717 HSOpts.Verbose = false;
718 ApplyHeaderSearchOptions(HS, HSOpts, CI.getLangOpts(),
719 CI.getTarget().getTriple());
720 }
721
722 llvm::StringMap<std::string>
723 computeModuleMapsForModules(ArrayRef<StringRef> ModuleNames) {
724 // Resolve any modulemaps passed directly first.
725 for (const std::string &Filename : CI.getFrontendOpts().ModuleMapFiles)
727 CI.getFileManager().getOptionalFileRef(Filename))
728 HS.parseModuleMapFile(*File, /*IsSystem=*/false,
729 /*ImplicitlyDiscovered=*/false);
730
731 const bool HasPrebuiltModules = !HSOpts.PrebuiltModuleFiles.empty() ||
732 !HSOpts.PrebuiltModulePaths.empty();
733
734 llvm::StringMap<std::string> Result;
735 // Then resolve modulemaps through header search.
736 for (StringRef Name : ModuleNames) {
737 // Skip over prebuilt modules.
738 if (HasPrebuiltModules && !HS.getPrebuiltModuleFileName(Name).empty())
739 continue;
741 Name, /*AllowExtraModuleMapSearch=*/true);
742 // Skip over modules that didn't find a modulemap.
743 if (!File)
744 continue;
745 // Canonicalize the path the same way as for the real scan.
746 SmallString<128> Path = File->getNameAsRequested();
748 Result[Name] = std::string(Path);
749 }
750 return Result;
751 }
752
753private:
754 CompilerInstance &CI;
755 HeaderSearchOptions HSOpts;
756 DiagnosticOptions DiagOpts;
757 DiagnosticsEngine Diags;
758 SourceManager SourceMgr;
759 HeaderSearch HS;
760};
761} // namespace
762
763class CompilerInstanceWithContext {
764 // Context
766 llvm::StringRef CWD;
767 std::vector<std::string> CommandLine;
768
769 // Context - compiler invocation
770 std::unique_ptr<CompilerInvocation> OriginalInvocation;
771
772 // Context - output options
773 std::unique_ptr<DependencyOutputOptions> OutputOpts;
774
775 // Context - stable directory handling
777 PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
778
779 // Context - used by AsyncScan's prescan pass
781
782 // Compiler Instance
783 std::unique_ptr<CompilerInstance> CIPtr;
784
785 // Source location offset.
786 int32_t SrcLocOffset = 0;
787
788 CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,
790 : Worker(Worker), CWD(CWD), CommandLine(CMD.begin(), CMD.end()) {}
791
792 bool initialize(DependencyActionController &Controller,
793 DiagnosticsEngine &DiagEngine,
795 {
796 auto LogLine = Worker.Service.getLogger().log();
797 LogLine.logArray("init_compiler_instance_with_context:", " ",
798 CommandLine);
799 }
800
801 ScanFS = Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
802 OriginalInvocation = createCompilerInvocation(CommandLine, DiagEngine);
803 if (!OriginalInvocation) {
804 DiagEngine.Report(diag::err_fe_expected_compiler_job)
805 << llvm::join(CommandLine, " ");
806 return false;
807 }
808
809 return initializeScanInstance(Controller, DiagEngine.getClient());
810 }
811
812 bool initializeScanInstance(DependencyActionController &Controller,
813 DiagnosticConsumer *DiagConsumer) {
814 assert(OriginalInvocation && ScanFS &&
815 "OriginalInvocation and ScanFS must be set before this call");
816
817 if (any(Worker.Service.getOpts().OptimizeArgs &
819 canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
820
821 // Create the CompilerInstance.
822 std::shared_ptr<ModuleCache> ModCache = makeInProcessModuleCache(
823 Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
824 CIPtr = std::make_unique<CompilerInstance>(
825 createScanCompilerInvocation(*OriginalInvocation, Worker.Service,
826 Controller),
827 Worker.PCHContainerOps, std::move(ModCache));
828 auto &CI = *CIPtr;
829
830 initializeScanCompilerInstance(CI, ScanFS, DiagConsumer, Worker.Service,
831 Worker.DepFS);
832
833 StableDirs = getInitialStableDirs(CI);
834 auto MaybePrebuiltModulesASTMap =
835 computePrebuiltModulesASTMap(CI, StableDirs);
836 if (!MaybePrebuiltModulesASTMap)
837 return false;
838
839 PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
840 OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
841
842 // We do not create the target in initializeScanCompilerInstance because
843 // setting it here is unique for by-name lookups. We create the target only
844 // once here, and the information is reused for all computeDependencies
845 // calls. We do not need to call createTarget explicitly if we go through
846 // CompilerInstance::ExecuteAction to perform scanning.
847 return CI.createTarget();
848 }
849
850 bool prescanModulesAsync(AsyncModuleCompiles &Compiles,
851 DependencyActionController &Controller) {
852 auto ModCache = makeInProcessModuleCache(
853 Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
854 CompilerInstance PrescanCI(
855 std::make_shared<CompilerInvocation>(CIPtr->getInvocation()),
856 Worker.PCHContainerOps, std::move(ModCache));
857
858 DiagnosticConsumer DiagConsumer;
859 initializeScanCompilerInstance(PrescanCI, ScanFS, &DiagConsumer,
860 Worker.Service, Worker.DepFS);
861
862 // FIXME: reuse the StableDirs/PrebuiltModuleASTMap computed in
863 // initialize().
864 SmallVector<StringRef> PrescanStableDirs = getInitialStableDirs(PrescanCI);
865 if (!computePrebuiltModulesASTMap(PrescanCI, PrescanStableDirs))
866 return false;
867
869 PrescanCI.getLangOpts().CompilingPCH = true;
870
871 runTUModulePrescan(PrescanCI, Worker.Service, Controller, Compiles);
872 return true;
873 }
874
875public:
876 static std::optional<CompilerInstanceWithContext>
878 DependencyScanningWorker &Worker, StringRef CWD,
879 ArrayRef<std::string> CC1CommandLine, DiagnosticsEngine &DiagEngine,
881 DependencyActionController &Controller) {
882 CompilerInstanceWithContext CIWC(Worker, CWD, CC1CommandLine);
883 if (!CIWC.initialize(Controller, DiagEngine, std::move(OverlayFS)))
884 return std::nullopt;
885 return std::move(CIWC);
886 }
887
888 /// Initialize from a cc1 command line, reporting diagnostics to
889 /// \p DiagConsumer.
890 static std::optional<CompilerInstanceWithContext>
892 DependencyScanningWorker &Worker, StringRef CWD,
893 ArrayRef<std::string> CC1CommandLine, DiagnosticConsumer &DiagConsumer,
895 DependencyActionController &Controller) {
896 auto FS = Worker.makeEffectiveVFS(CWD, OverlayFS);
897 auto DiagOpts = createScanningDiagOptions(CC1CommandLine);
898 auto DiagEngine =
899 CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DiagConsumer,
900 /*ShouldOwnClient=*/false);
901 return initializeFromCC1Commandline(Worker, CWD, CC1CommandLine,
902 *DiagEngine, std::move(OverlayFS),
903 Controller);
904 }
905
906 bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer,
907 DependencyActionController &Controller) {
908 Worker.Service.getLogger().log() << "start scan_by_name: " << ModuleName;
909 llvm::scope_exit ExitLogging([&] {
910 Worker.Service.getLogger().log() << "finish scan_by_name: " << ModuleName;
911 });
913 llvm::report_fatal_error("exceeded maximum by-name scans for worker");
914
915 assert(CIPtr && "CIPtr must be initialized before calling this method");
916 auto &CI = *CIPtr;
917
918 // We need to reset the diagnostics, so that the diagnostics issued
919 // during a previous computeDependencies call do not affect the current
920 // call. If we do not reset, we may inherit fatal errors from a previous
921 // call.
922 CI.getDiagnostics().Reset();
923
924 // We create this cleanup object because computeDependencies may exit
925 // early with errors.
926 llvm::scope_exit CleanUp([&]() {
928 // The preprocessor may not be created at the entry of this method,
929 // but it must have been created when this method returns, whether
930 // there are errors during scanning or not.
932 });
933
935 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
936 Worker.Service,
937 /* The MDC's constructor makes a copy of the OriginalInvocation, so
938 we can pass it in without worrying that it might be changed across
939 invocations of computeDependencies. */
940 *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
941
942 CompilerInvocation ModuleInvocation(*OriginalInvocation);
943 if (!Controller.initialize(CI, ModuleInvocation))
944 return false;
945
946 if (!SrcLocOffset) {
947 // When SrcLocOffset is zero, we are at the beginning of the fake source
948 // file. In this case, we call BeginSourceFile to initialize.
949 std::unique_ptr<FrontendAction> Action =
950 std::make_unique<PreprocessOnlyAction>();
951 auto *InputFile = CI.getFrontendOpts().Inputs.begin();
952 bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
953 assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
954 (void)ActionBeginSucceeded;
955 }
956
957 Preprocessor &PP = CI.getPreprocessor();
959 FileID MainFileID = SM.getMainFileID();
960 SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
961 SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
962 PPCallbacks *CB = nullptr;
963 if (!SrcLocOffset) {
964 // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
965 // the preprocessor.
966 bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
967 assert(!PPFailed && "Preprocess must be able to enter the main file.");
968 (void)PPFailed;
969 CB = MDC->getPPCallbacks();
970 } else {
971 // When SrcLocOffset is non-zero, the preprocessor has already been
972 // initialized through a previous call of computeDependencies. We want to
973 // preserve the PP's state, hence we do not call EnterSourceFile again.
974 MDC->attachToPreprocessor(PP);
975 CB = MDC->getPPCallbacks();
976
977 FileID PrevFID;
979 SM.getFileCharacteristic(IDLocation);
980 CB->LexedFileChanged(MainFileID,
982 FileType, PrevFID, IDLocation);
983 }
984
985 // FIXME: Scan modules asynchronously here as well.
986
987 SrcLocOffset++;
989 IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
990 Path.emplace_back(IDLocation, ModuleID);
991 auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden,
992 /*IsInclusionDirective=*/false);
993
994 assert(CB && "Must have PPCallbacks after module loading");
995 CB->moduleImport(SourceLocation(), Path, ModResult);
996
997 if (!ModResult)
998 return false;
999
1001 return false;
1002
1003 MDC->run(Consumer);
1004 MDC->applyDiscoveredDependencies(ModuleInvocation);
1005
1006 bool Success = ModuleInvocation.withCowRef<bool>(
1007 [&](CowCompilerInvocation &CowModuleInvocation) {
1008 return Controller.finalize(CI, CowModuleInvocation);
1009 });
1010 if (!Success)
1011 return false;
1012
1013 Consumer.handleBuildCommand(
1014 {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
1015
1016 return true;
1017 }
1018
1019 llvm::StringMap<std::string>
1021 assert(CIPtr && "CIPtr must be initialized before calling this method");
1022 return ModuleMapLookup(*CIPtr).computeModuleMapsForModules(ModuleNames);
1023 }
1024
1025 std::shared_ptr<ModuleDepCollector>
1027 DependencyActionController &Controller) {
1028 assert(CIPtr && "CIPtr must be initialized before calling this method");
1029 auto &CI = *CIPtr;
1030
1031 std::optional<AsyncModuleCompiles> AsyncCompiles;
1032 if (Worker.Service.getOpts().AsyncScanModules) {
1033 AsyncCompiles.emplace();
1034 if (!prescanModulesAsync(*AsyncCompiles, Controller))
1035 return nullptr;
1036 }
1037
1039 CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
1040 Worker.Service, *OriginalInvocation, Controller, PrebuiltModuleASTMap,
1041 StableDirs);
1042
1044 return nullptr;
1045
1046 if (!Controller.initialize(CI, *OriginalInvocation))
1047 return nullptr;
1048
1050 if (!CI.ExecuteAction(Action))
1051 return nullptr;
1052
1053 MDC->run(Consumer);
1054 if (!applyAndReport(*MDC, *OriginalInvocation, Consumer, Controller,
1055 CommandLine[0]))
1056 return nullptr;
1057 return MDC;
1058 }
1059
1061 CompilerInvocation &ModuleInvocation,
1062 DependencyConsumer &Consumer,
1063 DependencyActionController &Controller,
1064 StringRef Executable) {
1065 MDC.applyDiscoveredDependencies(ModuleInvocation);
1066 bool Success = ModuleInvocation.withCowRef<bool>(
1067 [&](CowCompilerInvocation &CowModuleInvocation) {
1068 return Controller.finalize(*CIPtr, CowModuleInvocation);
1069 });
1070 if (!Success)
1071 return false;
1072 Consumer.handleBuildCommand(
1073 {Executable.str(), ModuleInvocation.getCC1CommandLine()});
1074 return true;
1075 }
1076};
1077} // namespace dependencies
1078} // namespace clang
1079
1083 : Service(Service) {
1084 PCHContainerOps = std::make_shared<PCHContainerOperations>();
1085 // We need to read object files from PCH built outside the scanner.
1086 PCHContainerOps->registerReader(
1087 std::make_unique<ObjectFilePCHContainerReader>());
1088 // The scanner itself writes only raw ast files.
1089 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
1090
1091 auto BaseFS = Service.getOpts().MakeVFS();
1092
1093 if (Service.getOpts().TraceVFS) {
1094 TracingFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(
1095 std::move(BaseFS));
1096 BaseFS = TracingFS;
1097 }
1098
1099 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
1100 Service, std::move(BaseFS), std::move(LocalFS));
1101}
1102
1104
1107 StringRef WorkingDirectory,
1110 if (OverlayFS) {
1111 auto NewFS =
1112 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(FS));
1113 NewFS->pushOverlay(std::move(OverlayFS));
1114 FS = std::move(NewFS);
1115 }
1116 FS->setCurrentWorkingDirectory(WorkingDirectory);
1117 return FS;
1118}
1119
1121 StringRef WorkingDirectory, ArrayRef<ArrayRef<std::string>> CommandLines,
1122 DependencyConsumer &DepConsumer, DependencyActionController &Controller,
1123 DiagnosticConsumer &DiagConsumer,
1125 auto FS = makeEffectiveVFS(WorkingDirectory, OverlayFS);
1126
1127 bool Scanned = false;
1128 std::shared_ptr<ModuleDepCollector> MDC;
1129 std::optional<CompilerInstanceWithContext> CIWC;
1130
1131 const bool Success = llvm::all_of(CommandLines, [&](const auto &Cmd) {
1132 if (StringRef(Cmd[1]) != "-cc1") {
1133 // Non-clang command. Just pass through to the dependency consumer.
1134 DepConsumer.handleBuildCommand(
1135 {Cmd.front(), {Cmd.begin() + 1, Cmd.end()}});
1136 return true;
1137 }
1138
1139 Service.getLogger().log().logArray("starting scanning command:", " ", Cmd);
1140 llvm::scope_exit ExitLogging([&] {
1141 Service.getLogger().log().logArray("finished scanning command:", " ",
1142 Cmd);
1143 });
1144
1145 auto DiagOpts = createScanningDiagOptions(Cmd);
1146 auto DiagEngine =
1147 CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DiagConsumer,
1148 /*ShouldOwnClient=*/false);
1149 if (!Scanned) {
1150 // Scanning runs once for the first -cc1 invocation in a chain of driver
1151 // jobs.
1152 // For any dependent jobs, reuse the scanning result and just update the
1153 // new invocation.
1154 // FIXME: to support multi-arch builds, each arch requires a separate
1155 // scan.
1156 Scanned = true;
1158 *this, WorkingDirectory, Cmd, *DiagEngine, OverlayFS, Controller);
1159 if (!Result)
1160 return false;
1161 CIWC.emplace(std::move(*Result));
1162 MDC = CIWC->scanTranslationUnit(DepConsumer, Controller);
1163 return MDC != nullptr;
1164 }
1165
1166 auto Invocation = createCompilerInvocation(Cmd, *DiagEngine);
1167 if (!Invocation)
1168 return false;
1169
1170 // The first cc1 is canonicalized in initializeScanInstance; each sibling
1171 // invocation must likewise be canonicalized before its cc1 command line is
1172 // emitted. This is mostly relevant for multi-arch jobs where we currently
1173 // do not do re-scans.
1174 if (any(Service.getOpts().OptimizeArgs & ScanningOptimizations::Macros))
1175 canonicalizeDefines(Invocation->getPreprocessorOpts());
1176
1177 assert(CIWC && "Must have an initialized CIWC");
1178 return CIWC->applyAndReport(*MDC, *Invocation, DepConsumer, Controller,
1179 Cmd.front());
1180 });
1181
1182 return Success && Scanned;
1183}
1184
1186 StringRef CWD, ArrayRef<std::string> CC1CommandLine,
1188 DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
1189 llvm::function_ref<std::optional<std::string>()> getNextName,
1190 DependencyConsumer &DepConsumer) {
1191 std::optional<CompilerInstanceWithContext> CIWC =
1193 *this, CWD, CC1CommandLine, DiagConsumer, std::move(OverlayFS),
1194 Controller);
1195 if (!CIWC)
1196 return false;
1197
1198 bool AllScansSucceeded = true;
1199 while (std::optional<std::string> NextName = getNextName()) {
1200 bool Success =
1201 CIWC->computeDependencies(*NextName, DepConsumer, Controller);
1202 DepConsumer.finishQuery(*NextName, Success);
1203 AllScansSucceeded = AllScansSucceeded && Success;
1204 }
1205 return AllScansSucceeded;
1206}
1207
1208std::optional<llvm::StringMap<std::string>>
1210 StringRef CWD, ArrayRef<std::string> CC1CommandLine,
1212 DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
1213 ArrayRef<StringRef> ModuleNames) {
1214 std::optional<CompilerInstanceWithContext> CIWC =
1216 *this, CWD, CC1CommandLine, DiagConsumer, std::move(OverlayFS),
1217 Controller);
1218 if (!CIWC)
1219 return std::nullopt;
1220 return CIWC->computeModuleMapsForModules(ModuleNames);
1221}
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)
Result
Implement __builtin_bit_cast and related operations.
Defines the clang::Preprocessor interface.
This file declares semantic analysis for OpenACC constructs and clauses.
Abstract interface for callback invocations by the ASTReader.
Definition ASTReader.h:117
@ ARR_Missing
The client can handle an AST file that cannot load because it is missing.
Definition ASTReader.h:1828
@ ARR_OutOfDate
The client can handle an AST file that cannot load because it is out-of-date relative to its input fi...
Definition ASTReader.h:1832
@ ARR_TreatModuleWithErrorsAsOutOfDate
If a module file is marked with errors treat it as out-of-date so the caller can rebuild it.
Definition ASTReader.h:1845
static bool readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, const ModuleCache &ModCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities=ARR_ConfigurationMismatch|ARR_OutOfDate)
Read the control block for the named AST file.
@ Success
The control block was read successfully.
Definition ASTReader.h:450
@ OutOfDate
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition ASTReader.h:460
@ Missing
The AST file was missing.
Definition ASTReader.h:456
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override
Attempt to load the given module.
void createFileManager()
Create the file manager and replace any existing one with it.
FileManager & getFileManager() const
Return the current file manager to the caller.
ModuleCache & getModuleCache() const
void addDependencyCollector(std::shared_ptr< DependencyCollector > Listener)
Preprocessor & getPreprocessor() const
Return the current preprocessor.
void createVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS=llvm::vfs::getRealFileSystem(), DiagnosticConsumer *DC=nullptr)
Create a virtual file system instance based on the invocation.
FrontendOptions & getFrontendOpts()
HeaderSearchOptions & getHeaderSearchOpts()
void createSourceManager()
Create the source manager and replace any existing one with it.
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
TargetInfo & getTarget() const
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...
Used for handling and querying diagnostic IDs.
Options for controlling the compiler diagnostics engine.
std::vector< std::string > Warnings
The list of -W... options used to alter the diagnostic mappings, with the prefixes removed.
std::string DiagnosticSerializationFile
The file to serialize diagnostics to (non-appending).
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:241
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasErrorOccurred() const
Definition Diagnostic.h:913
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition Diagnostic.h:721
DiagnosticConsumer * getClient()
Definition Diagnostic.h:645
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
llvm::vfs::FileSystem & getVirtualFileSystem() const
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Get a FileEntryRef if it exists, without doing anything on error.
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.
std::vector< std::string > ModuleMapFiles
The list of module map files to load before processing the input.
HeaderSearchOptions - Helper class for storing options related to the initialization of the HeaderSea...
unsigned Verbose
Whether header search information should be output as for -v.
unsigned LazyLoadModuleMaps
Whether modules from module maps should only be loaded when used, not just when parsed.
std::map< std::string, std::string, std::less<> > PrebuiltModuleFiles
The mapping of module names to prebuilt module files.
std::vector< std::string > PrebuiltModulePaths
The directories used to load 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.).
bool parseModuleMapFile(FileEntryRef File, bool IsSystem, bool ImplicitlyDiscovered)
Parse the module map File, without loading the modules.
ModuleFileName getPrebuiltModuleFileName(StringRef ModuleName, bool FileMapOnly=false)
Retrieve the name of the prebuilt module file that should be used to load a module with the given nam...
OptionalFileEntryRef lookupModuleMapFileForModule(StringRef ModuleName, bool AllowExtraModuleMapSearch=false)
Find the module map that defines the top-level module ModuleName, without loading it.
ModuleFileName getCachedModuleFileName(Module *Module)
Retrieve the name of the cached module file that should be used to load the given module.
ModuleMap & getModuleMap()
Retrieve the module map.
One of these records is kept for each identifier that is lexed.
A diagnostic client that ignores all diagnostics.
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.
bool empty() const
Checks whether the module file name is empty.
Definition Module.h:194
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.
std::error_code canonicalizeModuleMapPath(SmallVectorImpl< char > &Path)
Canonicalize Path in a manner suitable for a module map file.
@ Hidden
All of the names in this module are hidden.
Definition Module.h:648
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Definition Module.h:943
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
virtual void LexedFileChanged(FileID FID, LexedFileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID, SourceLocation Loc)
Callback invoked whenever the Lexer moves to a different file for lexing.
Definition PPCallbacks.h:72
virtual void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported)
Callback invoked whenever there was an explicit module-import syntax.
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool SingleModuleParseMode
When enabled, preprocessor is in a mode for parsing a single module only.
std::vector< std::pair< std::string, bool > > Macros
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile=true)
Add a source file to the top of the include stack and start lexing tokens from it instead of the curr...
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
SourceManager & getSourceManager() const
Preprocessor-based frontend action that also loads PCH files.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
FileID getMainFileID() const
Returns the FileID of the main source file.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const
Return the file characteristic of the specified source location, indicating whether this is a normal ...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
The base class of the type hierarchy.
Definition TypeBase.h:1879
static std::optional< CompilerInstanceWithContext > initializeFromCC1Commandline(DependencyScanningWorker &Worker, StringRef CWD, ArrayRef< std::string > CC1CommandLine, DiagnosticConsumer &DiagConsumer, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS, DependencyActionController &Controller)
Initialize from a cc1 command line, reporting diagnostics to DiagConsumer.
std::shared_ptr< ModuleDepCollector > scanTranslationUnit(DependencyConsumer &Consumer, DependencyActionController &Controller)
bool applyAndReport(ModuleDepCollector &MDC, CompilerInvocation &ModuleInvocation, DependencyConsumer &Consumer, DependencyActionController &Controller, StringRef Executable)
llvm::StringMap< std::string > computeModuleMapsForModules(ArrayRef< StringRef > ModuleNames)
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.
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.
DependencyScanningWorker(DependencyScanningService &Service, IntrusiveRefCntPtr< llvm::vfs::FileSystem > LocalFS=nullptr)
Construct a dependency scanning worker.
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.
std::optional< llvm::StringMap< std::string > > computeModuleMapsForModules(StringRef CWD, ArrayRef< std::string > CC1CommandLine, IntrusiveRefCntPtr< llvm::vfs::FileSystem > OverlayFS, DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller, ArrayRef< StringRef > ModuleNames)
Creates a compiler instance to return a map of module names to their defined module map path.
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.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:196
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
void ApplyHeaderSearchOptions(HeaderSearch &HS, const HeaderSearchOptions &HSOpts, const LangOptions &Lang, const llvm::Triple &triple)
Apply the header search options to get given HeaderSearch object.
@ Success
Annotation was successful.
Definition Parser.h:65
@ Worker
'worker' clause, allowed on 'loop', Combined, and 'routine' directives.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
Definition Linkage.h:54
@ Result
The result type of a method or function.
Definition TypeBase.h:906
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
unsigned long uint64_t
int __ovld __cnfn any(char)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
ScanningMode Mode
Whether to use optimized dependency directive scan or full preprocessing.
bool ValidateAgainstInvalidatedPaths
Whether scanning modules validate their directory deps against paths reported via DependencyScanningS...
bool EmitWarnings
Whether the scanner should emit warnings.
std::time_t BuildSessionTimestamp
The build session timestamp for validate-once-per-build-session logic.
ScanningOptimizations OptimizeArgs
How to optimize resulting explicit module command lines.
This is used to identify a specific module.