clang 22.0.0git
DependencyScanningWorker.cpp
Go to the documentation of this file.
1//===- DependencyScanningWorker.cpp - clang-scan-deps 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
14#include "clang/Driver/Driver.h"
15#include "clang/Driver/Job.h"
16#include "clang/Driver/Tool.h"
27#include "llvm/ADT/IntrusiveRefCntPtr.h"
28#include "llvm/Support/Allocator.h"
29#include "llvm/Support/Error.h"
30#include "llvm/Support/MemoryBuffer.h"
31#include "llvm/TargetParser/Host.h"
32#include <optional>
33
34using namespace clang;
35using namespace tooling;
36using namespace dependencies;
37
38namespace {
39
40/// Forwards the gatherered dependencies to the consumer.
41class DependencyConsumerForwarder : public DependencyFileGenerator {
42public:
43 DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
44 StringRef WorkingDirectory, DependencyConsumer &C)
45 : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
46 Opts(std::move(Opts)), C(C) {}
47
48 void finishedMainFile(DiagnosticsEngine &Diags) override {
49 C.handleDependencyOutputOpts(*Opts);
50 llvm::SmallString<256> CanonPath;
51 for (const auto &File : getDependencies()) {
52 CanonPath = File;
53 llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
54 llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath);
55 C.handleFileDependency(CanonPath);
56 }
57 }
58
59private:
60 StringRef WorkingDirectory;
61 std::unique_ptr<DependencyOutputOptions> Opts;
63};
64
65static bool checkHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
66 const HeaderSearchOptions &ExistingHSOpts,
67 DiagnosticsEngine *Diags,
68 const LangOptions &LangOpts) {
69 if (LangOpts.Modules) {
70 if (HSOpts.VFSOverlayFiles != ExistingHSOpts.VFSOverlayFiles) {
71 if (Diags) {
72 Diags->Report(diag::warn_pch_vfsoverlay_mismatch);
73 auto VFSNote = [&](int Type, ArrayRef<std::string> VFSOverlays) {
74 if (VFSOverlays.empty()) {
75 Diags->Report(diag::note_pch_vfsoverlay_empty) << Type;
76 } else {
77 std::string Files = llvm::join(VFSOverlays, "\n");
78 Diags->Report(diag::note_pch_vfsoverlay_files) << Type << Files;
79 }
80 };
81 VFSNote(0, HSOpts.VFSOverlayFiles);
82 VFSNote(1, ExistingHSOpts.VFSOverlayFiles);
83 }
84 }
85 }
86 return false;
87}
88
89using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
90
91/// A listener that collects the imported modules and the input
92/// files. While visiting, collect vfsoverlays and file inputs that determine
93/// whether prebuilt modules fully resolve in stable directories.
94class PrebuiltModuleListener : public ASTReaderListener {
95public:
96 PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
97 llvm::SmallVector<std::string> &NewModuleFiles,
98 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
99 const HeaderSearchOptions &HSOpts,
100 const LangOptions &LangOpts, DiagnosticsEngine &Diags,
101 const ArrayRef<StringRef> StableDirs)
102 : PrebuiltModuleFiles(PrebuiltModuleFiles),
103 NewModuleFiles(NewModuleFiles),
104 PrebuiltModulesASTMap(PrebuiltModulesASTMap), ExistingHSOpts(HSOpts),
105 ExistingLangOpts(LangOpts), Diags(Diags), StableDirs(StableDirs) {}
106
107 bool needsImportVisitation() const override { return true; }
108 bool needsInputFileVisitation() override { return true; }
109 bool needsSystemInputFileVisitation() override { return true; }
110
111 /// Accumulate the modules are transitively depended on by the initial
112 /// prebuilt module.
113 void visitImport(StringRef ModuleName, StringRef Filename) override {
114 if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
115 NewModuleFiles.push_back(Filename.str());
116
117 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(Filename);
118 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
119 if (PrebuiltMapEntry.second)
120 PrebuiltModule.setInStableDir(!StableDirs.empty());
121
122 if (auto It = PrebuiltModulesASTMap.find(CurrentFile);
123 It != PrebuiltModulesASTMap.end() && CurrentFile != Filename)
124 PrebuiltModule.addDependent(It->getKey());
125 }
126
127 /// For each input file discovered, check whether it's external path is in a
128 /// stable directory. Traversal is stopped if the current module is not
129 /// considered stable.
130 bool visitInputFile(StringRef FilenameAsRequested, StringRef Filename,
131 bool isSystem, bool isOverridden,
132 bool isExplicitModule) override {
133 if (StableDirs.empty())
134 return false;
135 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
136 if ((PrebuiltEntryIt == PrebuiltModulesASTMap.end()) ||
137 (!PrebuiltEntryIt->second.isInStableDir()))
138 return false;
139
140 PrebuiltEntryIt->second.setInStableDir(
141 isPathInStableDir(StableDirs, Filename));
142 return PrebuiltEntryIt->second.isInStableDir();
143 }
144
145 /// Update which module that is being actively traversed.
146 void visitModuleFile(StringRef Filename,
147 serialization::ModuleKind Kind) override {
148 // If the CurrentFile is not
149 // considered stable, update any of it's transitive dependents.
150 auto PrebuiltEntryIt = PrebuiltModulesASTMap.find(CurrentFile);
151 if ((PrebuiltEntryIt != PrebuiltModulesASTMap.end()) &&
152 !PrebuiltEntryIt->second.isInStableDir())
153 PrebuiltEntryIt->second.updateDependentsNotInStableDirs(
154 PrebuiltModulesASTMap);
155 CurrentFile = Filename;
156 }
157
158 /// Check the header search options for a given module when considering
159 /// if the module comes from stable directories.
161 StringRef ModuleFilename,
162 StringRef SpecificModuleCachePath,
163 bool Complain) override {
164
165 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
166 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
167 if (PrebuiltMapEntry.second)
168 PrebuiltModule.setInStableDir(!StableDirs.empty());
169
170 if (PrebuiltModule.isInStableDir())
171 PrebuiltModule.setInStableDir(areOptionsInStableDir(StableDirs, HSOpts));
172
173 return false;
174 }
175
176 /// Accumulate vfsoverlays used to build these prebuilt modules.
178 bool Complain) override {
179
180 auto PrebuiltMapEntry = PrebuiltModulesASTMap.try_emplace(CurrentFile);
181 PrebuiltModuleASTAttrs &PrebuiltModule = PrebuiltMapEntry.first->second;
182 if (PrebuiltMapEntry.second)
183 PrebuiltModule.setInStableDir(!StableDirs.empty());
184
185 PrebuiltModule.setVFS(
186 llvm::StringSet<>(llvm::from_range, HSOpts.VFSOverlayFiles));
187
188 return checkHeaderSearchPaths(
189 HSOpts, ExistingHSOpts, Complain ? &Diags : nullptr, ExistingLangOpts);
190 }
191
192private:
193 PrebuiltModuleFilesT &PrebuiltModuleFiles;
194 llvm::SmallVector<std::string> &NewModuleFiles;
195 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap;
196 const HeaderSearchOptions &ExistingHSOpts;
197 const LangOptions &ExistingLangOpts;
198 DiagnosticsEngine &Diags;
199 std::string CurrentFile;
200 const ArrayRef<StringRef> StableDirs;
201};
202
203/// Visit the given prebuilt module and collect all of the modules it
204/// transitively imports and contributing input files.
205static bool visitPrebuiltModule(StringRef PrebuiltModuleFilename,
207 PrebuiltModuleFilesT &ModuleFiles,
208 PrebuiltModulesAttrsMap &PrebuiltModulesASTMap,
209 DiagnosticsEngine &Diags,
210 const ArrayRef<StringRef> StableDirs) {
211 // List of module files to be processed.
213
214 PrebuiltModuleListener Listener(ModuleFiles, Worklist, PrebuiltModulesASTMap,
216 Diags, StableDirs);
217
218 Listener.visitModuleFile(PrebuiltModuleFilename,
221 PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
223 /*FindModuleFileExtensions=*/false, Listener,
224 /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
225 return true;
226
227 while (!Worklist.empty()) {
228 Listener.visitModuleFile(Worklist.back(), serialization::MK_ExplicitModule);
230 Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
232 /*FindModuleFileExtensions=*/false, Listener,
233 /*ValidateDiagnosticOptions=*/false))
234 return true;
235 }
236 return false;
237}
238
239/// Transform arbitrary file name into an object-like file name.
240static std::string makeObjFileName(StringRef FileName) {
241 SmallString<128> ObjFileName(FileName);
242 llvm::sys::path::replace_extension(ObjFileName, "o");
243 return std::string(ObjFileName);
244}
245
246/// Deduce the dependency target based on the output file and input files.
247static std::string
248deduceDepTarget(const std::string &OutputFile,
249 const SmallVectorImpl<FrontendInputFile> &InputFiles) {
250 if (OutputFile != "-")
251 return OutputFile;
252
253 if (InputFiles.empty() || !InputFiles.front().isFile())
254 return "clang-scan-deps\\ dependency";
255
256 return makeObjFileName(InputFiles.front().getFile());
257}
258
259/// Sanitize diagnostic options for dependency scan.
260static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
261 // Don't print 'X warnings and Y errors generated'.
262 DiagOpts.ShowCarets = false;
263 // Don't write out diagnostic file.
264 DiagOpts.DiagnosticSerializationFile.clear();
265 // Don't emit warnings except for scanning specific warnings.
266 // TODO: It would be useful to add a more principled way to ignore all
267 // warnings that come from source code. The issue is that we need to
268 // ignore warnings that could be surpressed by
269 // `#pragma clang diagnostic`, while still allowing some scanning
270 // warnings for things we're not ready to turn into errors yet.
271 // See `test/ClangScanDeps/diagnostic-pragmas.c` for an example.
272 llvm::erase_if(DiagOpts.Warnings, [](StringRef Warning) {
273 return llvm::StringSwitch<bool>(Warning)
274 .Cases("pch-vfs-diff", "error=pch-vfs-diff", false)
275 .StartsWith("no-error=", false)
276 .Default(true);
277 });
278}
279
280// Clang implements -D and -U by splatting text into a predefines buffer. This
281// allows constructs such as `-DFඞ=3 "-D F\u{0D9E} 4 3 2”` to be accepted and
282// define the same macro, or adding C++ style comments before the macro name.
283//
284// This function checks that the first non-space characters in the macro
285// obviously form an identifier that can be uniqued on without lexing. Failing
286// to do this could lead to changing the final definition of a macro.
287//
288// We could set up a preprocessor and actually lex the name, but that's very
289// heavyweight for a situation that will almost never happen in practice.
290static std::optional<StringRef> getSimpleMacroName(StringRef Macro) {
291 StringRef Name = Macro.split("=").first.ltrim(" \t");
292 std::size_t I = 0;
293
294 auto FinishName = [&]() -> std::optional<StringRef> {
295 StringRef SimpleName = Name.slice(0, I);
296 if (SimpleName.empty())
297 return std::nullopt;
298 return SimpleName;
299 };
300
301 for (; I != Name.size(); ++I) {
302 switch (Name[I]) {
303 case '(': // Start of macro parameter list
304 case ' ': // End of macro name
305 case '\t':
306 return FinishName();
307 case '_':
308 continue;
309 default:
310 if (llvm::isAlnum(Name[I]))
311 continue;
312 return std::nullopt;
313 }
314 }
315 return FinishName();
316}
317
318static void canonicalizeDefines(PreprocessorOptions &PPOpts) {
319 using MacroOpt = std::pair<StringRef, std::size_t>;
320 std::vector<MacroOpt> SimpleNames;
321 SimpleNames.reserve(PPOpts.Macros.size());
322 std::size_t Index = 0;
323 for (const auto &M : PPOpts.Macros) {
324 auto SName = getSimpleMacroName(M.first);
325 // Skip optimizing if we can't guarantee we can preserve relative order.
326 if (!SName)
327 return;
328 SimpleNames.emplace_back(*SName, Index);
329 ++Index;
330 }
331
332 llvm::stable_sort(SimpleNames, llvm::less_first());
333 // Keep the last instance of each macro name by going in reverse
334 auto NewEnd = std::unique(
335 SimpleNames.rbegin(), SimpleNames.rend(),
336 [](const MacroOpt &A, const MacroOpt &B) { return A.first == B.first; });
337 SimpleNames.erase(SimpleNames.begin(), NewEnd.base());
338
339 // Apply permutation.
340 decltype(PPOpts.Macros) NewMacros;
341 NewMacros.reserve(SimpleNames.size());
342 for (std::size_t I = 0, E = SimpleNames.size(); I != E; ++I) {
343 std::size_t OriginalIndex = SimpleNames[I].second;
344 // We still emit undefines here as they may be undefining a predefined macro
345 NewMacros.push_back(std::move(PPOpts.Macros[OriginalIndex]));
346 }
347 std::swap(PPOpts.Macros, NewMacros);
348}
349
350class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter {
352
353public:
354 ScanningDependencyDirectivesGetter(FileManager &FileMgr) : DepFS(nullptr) {
355 FileMgr.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &FS) {
356 auto *DFS = llvm::dyn_cast<DependencyScanningWorkerFilesystem>(&FS);
357 if (DFS) {
358 assert(!DepFS && "Found multiple scanning VFSs");
359 DepFS = DFS;
360 }
361 });
362 assert(DepFS && "Did not find scanning VFS");
363 }
364
365 std::unique_ptr<DependencyDirectivesGetter>
366 cloneFor(FileManager &FileMgr) override {
367 return std::make_unique<ScanningDependencyDirectivesGetter>(FileMgr);
368 }
369
370 std::optional<ArrayRef<dependency_directives_scan::Directive>>
371 operator()(FileEntryRef File) override {
372 return DepFS->getDirectiveTokens(File.getName());
373 }
374};
375
376/// A clang tool that runs the preprocessor in a mode that's optimized for
377/// dependency scanning for the given compiler invocation.
378class DependencyScanningAction {
379public:
380 DependencyScanningAction(
381 DependencyScanningService &Service, StringRef WorkingDirectory,
382 DependencyConsumer &Consumer, DependencyActionController &Controller,
384 std::optional<StringRef> ModuleName = std::nullopt)
385 : Service(Service), WorkingDirectory(WorkingDirectory),
386 Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)),
387 ModuleName(ModuleName) {}
388
389 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
391 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
392 DiagnosticConsumer *DiagConsumer) {
393 // Make a deep copy of the original Clang invocation.
394 CompilerInvocation OriginalInvocation(*Invocation);
395 if (any(Service.getOptimizeArgs() & ScanningOptimizations::Macros))
396 canonicalizeDefines(OriginalInvocation.getPreprocessorOpts());
397
398 if (Scanned) {
399 // Scanning runs once for the first -cc1 invocation in a chain of driver
400 // jobs. For any dependent jobs, reuse the scanning result and just
401 // update the LastCC1Arguments to correspond to the new invocation.
402 // FIXME: to support multi-arch builds, each arch requires a separate scan
403 setLastCC1Arguments(std::move(OriginalInvocation));
404 return true;
405 }
406
407 Scanned = true;
408
409 // Create a compiler instance to handle the actual work.
410 auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
411 ScanInstanceStorage.emplace(std::move(Invocation),
412 std::move(PCHContainerOps), ModCache.get());
413 CompilerInstance &ScanInstance = *ScanInstanceStorage;
414 ScanInstance.setBuildingModule(false);
415
416 // Create the compiler's actual diagnostics engine.
417 sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
418 assert(!DiagConsumerFinished && "attempt to reuse finished consumer");
419 ScanInstance.createDiagnostics(*FS, DiagConsumer,
420 /*ShouldOwnClient=*/false);
421 if (!ScanInstance.hasDiagnostics())
422 return false;
423
425 true;
426
429 Service.getBuildSessionTimestamp();
430
431 ScanInstance.getFrontendOpts().DisableFree = false;
432 ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false;
433 ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false;
434 // This will prevent us compiling individual modules asynchronously since
435 // FileManager is not thread-safe, but it does improve performance for now.
436 ScanInstance.getFrontendOpts().ModulesShareFileManager = true;
437 ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw";
439 any(Service.getOptimizeArgs() & ScanningOptimizations::VFS);
440
441 // Support for virtual file system overlays.
443 ScanInstance.getDiagnostics(),
444 std::move(FS));
445
446 // Create a new FileManager to match the invocation's FileSystemOptions.
447 auto *FileMgr = ScanInstance.createFileManager(FS);
448
449 // Use the dependency scanning optimized file system if requested to do so.
450 if (DepFS) {
451 StringRef ModulesCachePath =
453
455 if (!ModulesCachePath.empty())
456 DepFS->setBypassedPathPrefix(ModulesCachePath);
457
459 std::make_unique<ScanningDependencyDirectivesGetter>(*FileMgr));
460 }
461
462 ScanInstance.createSourceManager(*FileMgr);
463
464 // Create a collection of stable directories derived from the ScanInstance
465 // for determining whether module dependencies would fully resolve from
466 // those directories.
468 const StringRef Sysroot = ScanInstance.getHeaderSearchOpts().Sysroot;
469 if (!Sysroot.empty() &&
470 (llvm::sys::path::root_directory(Sysroot) != Sysroot))
471 StableDirs = {Sysroot, ScanInstance.getHeaderSearchOpts().ResourceDir};
472
473 // Store a mapping of prebuilt module files and their properties like header
474 // search options. This will prevent the implicit build to create duplicate
475 // modules and will force reuse of the existing prebuilt module files
476 // instead.
477 PrebuiltModulesAttrsMap PrebuiltModulesASTMap;
478
479 if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
480 if (visitPrebuiltModule(
482 ScanInstance,
484 PrebuiltModulesASTMap, ScanInstance.getDiagnostics(), StableDirs))
485 return false;
486
487 // Create the dependency collector that will collect the produced
488 // dependencies.
489 //
490 // This also moves the existing dependency output options from the
491 // invocation to the collector. The options in the invocation are reset,
492 // which ensures that the compiler won't create new dependency collectors,
493 // and thus won't write out the extra '.d' files to disk.
494 auto Opts = std::make_unique<DependencyOutputOptions>();
495 std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts());
496 // We need at least one -MT equivalent for the generator of make dependency
497 // files to work.
498 if (Opts->Targets.empty())
499 Opts->Targets = {
500 deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile,
501 ScanInstance.getFrontendOpts().Inputs)};
502 Opts->IncludeSystemHeaders = true;
503
504 switch (Service.getFormat()) {
505 case ScanningOutputFormat::Make:
506 ScanInstance.addDependencyCollector(
507 std::make_shared<DependencyConsumerForwarder>(
508 std::move(Opts), WorkingDirectory, Consumer));
509 break;
510 case ScanningOutputFormat::P1689:
511 case ScanningOutputFormat::Full:
512 MDC = std::make_shared<ModuleDepCollector>(
513 Service, std::move(Opts), ScanInstance, Consumer, Controller,
514 OriginalInvocation, std::move(PrebuiltModulesASTMap), StableDirs);
515 ScanInstance.addDependencyCollector(MDC);
516 break;
517 }
518
519 // Consider different header search and diagnostic options to create
520 // different modules. This avoids the unsound aliasing of module PCMs.
521 //
522 // TODO: Implement diagnostic bucketing to reduce the impact of strict
523 // context hashing.
524 ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true;
529 true;
531
532 // Avoid some checks and module map parsing when loading PCM files.
533 ScanInstance.getPreprocessorOpts().ModulesCheckRelocated = false;
534
535 std::unique_ptr<FrontendAction> Action;
536
537 if (Service.getFormat() == ScanningOutputFormat::P1689)
538 Action = std::make_unique<PreprocessOnlyAction>();
539 else if (ModuleName)
540 Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
541 else
542 Action = std::make_unique<ReadPCHAndPreprocessAction>();
543
544 if (ScanInstance.getDiagnostics().hasErrorOccurred())
545 return false;
546
547 const bool Result = ScanInstance.ExecuteAction(*Action);
548
549 // ExecuteAction is responsible for calling finish.
550 DiagConsumerFinished = true;
551
552 if (Result)
553 setLastCC1Arguments(std::move(OriginalInvocation));
554
555 return Result;
556 }
557
558 bool hasScanned() const { return Scanned; }
559 bool hasDiagConsumerFinished() const { return DiagConsumerFinished; }
560
561 /// Take the cc1 arguments corresponding to the most recent invocation used
562 /// with this action. Any modifications implied by the discovered dependencies
563 /// will have already been applied.
564 std::vector<std::string> takeLastCC1Arguments() {
565 std::vector<std::string> Result;
566 std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
567 return Result;
568 }
569
570private:
571 void setLastCC1Arguments(CompilerInvocation &&CI) {
572 if (MDC)
573 MDC->applyDiscoveredDependencies(CI);
574 LastCC1Arguments = CI.getCC1CommandLine();
575 }
576
578 StringRef WorkingDirectory;
579 DependencyConsumer &Consumer;
580 DependencyActionController &Controller;
582 std::optional<StringRef> ModuleName;
583 std::optional<CompilerInstance> ScanInstanceStorage;
584 std::shared_ptr<ModuleDepCollector> MDC;
585 std::vector<std::string> LastCC1Arguments;
586 bool Scanned = false;
587 bool DiagConsumerFinished = false;
588};
589
590} // end anonymous namespace
591
595 : Service(Service) {
596 PCHContainerOps = std::make_shared<PCHContainerOperations>();
597 // We need to read object files from PCH built outside the scanner.
598 PCHContainerOps->registerReader(
599 std::make_unique<ObjectFilePCHContainerReader>());
600 // The scanner itself writes only raw ast files.
601 PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
602
603 if (Service.shouldTraceVFS())
604 FS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(std::move(FS));
605
606 switch (Service.getMode()) {
608 DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
609 Service.getSharedCache(), FS);
610 BaseFS = DepFS;
611 break;
613 DepFS = nullptr;
614 BaseFS = FS;
615 break;
616 }
617}
618
619static std::unique_ptr<DiagnosticOptions>
620createDiagOptions(const std::vector<std::string> &CommandLine) {
621 std::vector<const char *> CLI;
622 for (const std::string &Arg : CommandLine)
623 CLI.push_back(Arg.c_str());
624 auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
625 sanitizeDiagOpts(*DiagOpts);
626 return DiagOpts;
627}
628
630 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
631 DependencyConsumer &Consumer, DependencyActionController &Controller,
632 std::optional<llvm::MemoryBufferRef> TUBuffer) {
633 // Capture the emitted diagnostics and report them to the client
634 // in the case of a failure.
635 std::string DiagnosticOutput;
636 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
637 auto DiagOpts = createDiagOptions(CommandLine);
638 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
639
640 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
641 DiagPrinter, TUBuffer))
642 return llvm::Error::success();
643 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
644 llvm::inconvertibleErrorCode());
645}
646
648 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
649 DependencyConsumer &Consumer, DependencyActionController &Controller,
650 StringRef ModuleName) {
651 // Capture the emitted diagnostics and report them to the client
652 // in the case of a failure.
653 std::string DiagnosticOutput;
654 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
655 auto DiagOpts = createDiagOptions(CommandLine);
656 TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
657
658 if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
659 DiagPrinter, ModuleName))
660 return llvm::Error::success();
661 return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
662 llvm::inconvertibleErrorCode());
663}
664
668 llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
670 Argv.reserve(ArgStrs.size());
671 for (const std::string &Arg : ArgStrs)
672 Argv.push_back(Arg.c_str());
673
674 std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
675 Argv[0], llvm::sys::getDefaultTargetTriple(), Diags,
676 "clang LLVM compiler", FS);
677 Driver->setTitle("clang_based_tool");
678
679 llvm::BumpPtrAllocator Alloc;
680 bool CLMode = driver::IsClangCL(
681 driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1)));
682
683 if (llvm::Error E =
684 driver::expandResponseFiles(Argv, CLMode, Alloc, FS.get())) {
685 Diags.Report(diag::err_drv_expand_response_file)
686 << llvm::toString(std::move(E));
687 return false;
688 }
689
690 const std::unique_ptr<driver::Compilation> Compilation(
691 Driver->BuildCompilation(llvm::ArrayRef(Argv)));
692 if (!Compilation)
693 return false;
694
695 if (Compilation->containsError())
696 return false;
697
698 for (const driver::Command &Job : Compilation->getJobs()) {
699 if (!Callback(Job))
700 return false;
701 }
702 return true;
703}
704
706 std::vector<std::string> CommandLine, DependencyScanningAction &Action,
708 std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
709 DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {
710
711 // Save executable path before providing CommandLine to ToolInvocation
712 std::string Executable = CommandLine[0];
713
714 llvm::opt::ArgStringList Argv;
715 for (const std::string &Str : ArrayRef(CommandLine).drop_front())
716 Argv.push_back(Str.c_str());
717
718 auto Invocation = std::make_shared<CompilerInvocation>();
719 if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) {
720 // FIXME: Should we just go on like cc1_main does?
721 return false;
722 }
723
724 if (!Action.runInvocation(std::move(Invocation), std::move(FS),
725 PCHContainerOps, Diags.getClient()))
726 return false;
727
728 std::vector<std::string> Args = Action.takeLastCC1Arguments();
729 Consumer.handleBuildCommand({std::move(Executable), std::move(Args)});
730 return true;
731}
732
733bool DependencyScanningWorker::scanDependencies(
734 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
735 DependencyConsumer &Consumer, DependencyActionController &Controller,
737 std::optional<StringRef> ModuleName) {
738 std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
739 llvm::transform(CommandLine, CCommandLine.begin(),
740 [](const std::string &Str) { return Str.c_str(); });
741 auto DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
742 sanitizeDiagOpts(*DiagOpts);
743 auto Diags = CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DC,
744 /*ShouldOwnClient=*/false);
745
746 DependencyScanningAction Action(Service, WorkingDirectory, Consumer,
747 Controller, DepFS, ModuleName);
748
749 bool Success = false;
750 if (CommandLine[1] == "-cc1") {
751 Success = createAndRunToolInvocation(CommandLine, Action, FS,
752 PCHContainerOps, *Diags, Consumer);
753 } else {
755 CommandLine, *Diags, FS, [&](const driver::Command &Cmd) {
756 if (StringRef(Cmd.getCreator().getName()) != "clang") {
757 // Non-clang command. Just pass through to the dependency
758 // consumer.
759 Consumer.handleBuildCommand(
760 {Cmd.getExecutable(),
761 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
762 return true;
763 }
764
765 // Insert -cc1 comand line options into Argv
766 std::vector<std::string> Argv;
767 Argv.push_back(Cmd.getExecutable());
768 llvm::append_range(Argv, Cmd.getArguments());
769
770 // Create an invocation that uses the underlying file
771 // system to ensure that any file system requests that
772 // are made by the driver do not go through the
773 // dependency scanning filesystem.
774 return createAndRunToolInvocation(std::move(Argv), Action, FS,
775 PCHContainerOps, *Diags, Consumer);
776 });
777 }
778
779 if (Success && !Action.hasScanned())
780 Diags->Report(diag::err_fe_expected_compiler_job)
781 << llvm::join(CommandLine, " ");
782
783 // Ensure finish() is called even if we never reached ExecuteAction().
784 if (!Action.hasDiagConsumerFinished())
785 DC.finish();
786
787 return Success && Action.hasScanned();
788}
789
791 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
792 DependencyConsumer &Consumer, DependencyActionController &Controller,
793 DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
794 // Reset what might have been modified in the previous worker invocation.
795 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
796
797 std::optional<std::vector<std::string>> ModifiedCommandLine;
799
800 // If we're scanning based on a module name alone, we don't expect the client
801 // to provide us with an input file. However, the driver really wants to have
802 // one. Let's just make it up to make the driver happy.
803 if (TUBuffer) {
804 auto OverlayFS =
805 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
806 auto InMemoryFS =
807 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
808 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
809 auto InputPath = TUBuffer->getBufferIdentifier();
810 InMemoryFS->addFile(
811 InputPath, 0,
812 llvm::MemoryBuffer::getMemBufferCopy(TUBuffer->getBuffer()));
814 InMemoryFS;
815
816 OverlayFS->pushOverlay(InMemoryOverlay);
817 ModifiedFS = OverlayFS;
818 ModifiedCommandLine = CommandLine;
819 ModifiedCommandLine->emplace_back(InputPath);
820 }
821
822 const std::vector<std::string> &FinalCommandLine =
823 ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
824 auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
825
826 return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,
827 Controller, DC, FinalFS, /*ModuleName=*/std::nullopt);
828}
829
831 StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
832 DependencyConsumer &Consumer, DependencyActionController &Controller,
833 DiagnosticConsumer &DC, StringRef ModuleName) {
834 // Reset what might have been modified in the previous worker invocation.
835 BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
836
837 // If we're scanning based on a module name alone, we don't expect the client
838 // to provide us with an input file. However, the driver really wants to have
839 // one. Let's just make it up to make the driver happy.
840 auto OverlayFS =
841 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
842 auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
843 InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
844 SmallString<128> FakeInputPath;
845 // TODO: We should retry the creation if the path already exists.
846 llvm::sys::fs::createUniquePath(ModuleName + "-%%%%%%%%.input", FakeInputPath,
847 /*MakeAbsolute=*/false);
848 InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
849 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
850
851 OverlayFS->pushOverlay(InMemoryOverlay);
852 auto ModifiedCommandLine = CommandLine;
853 ModifiedCommandLine.emplace_back(FakeInputPath);
854
855 return scanDependencies(WorkingDirectory, ModifiedCommandLine, Consumer,
856 Controller, DC, OverlayFS, ModuleName);
857}
858
Expr * E
static bool createAndRunToolInvocation(std::vector< std::string > CommandLine, DependencyScanningAction &Action, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, std::shared_ptr< clang::PCHContainerOperations > &PCHContainerOps, DiagnosticsEngine &Diags, DependencyConsumer &Consumer)
static std::unique_ptr< DiagnosticOptions > createDiagOptions(const std::vector< std::string > &CommandLine)
static bool forEachDriverJob(ArrayRef< std::string > ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS, llvm::function_ref< bool(const driver::Command &Cmd)> Callback)
StringRef Filename
Definition: Format.cpp:3177
CompileCommand Cmd
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:117
virtual bool needsInputFileVisitation()
Returns true if this ASTReaderListener wants to receive the input files of the AST file via visitInpu...
Definition: ASTReader.h:232
virtual bool visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, bool isExplicitModule)
if needsInputFileVisitation returns true, this is called for each non-system input file of the AST Fi...
Definition: ASTReader.h:244
virtual bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts, bool Complain)
Receives the header search paths.
Definition: ASTReader.h:202
virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef ModuleFilename, StringRef SpecificModuleCachePath, bool Complain)
Receives the header search options.
Definition: ASTReader.h:186
virtual void visitImport(StringRef ModuleName, StringRef Filename)
If needsImportVisitation returns true, this is called for each AST file imported by this AST file.
Definition: ASTReader.h:267
virtual void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind)
This is called for each AST file loaded.
Definition: ASTReader.h:227
virtual bool needsImportVisitation() const
Returns true if this ASTReaderListener wants to receive the imports of the AST file via visitImport,...
Definition: ASTReader.h:263
virtual bool needsSystemInputFileVisitation()
Returns true if this ASTReaderListener wants to receive the system input files of the AST file via vi...
Definition: ASTReader.h:236
@ 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:1836
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.
Definition: ASTReader.cpp:5794
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void createSourceManager(FileManager &FileMgr)
Create the source manager and replace any existing one with it.
FileManager * createFileManager(IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS=nullptr)
Create the file manager and replace any existing one with it.
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
void createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
FileManager & getFileManager() const
Return the current file manager to the caller.
ModuleCache & getModuleCache() const
void addDependencyCollector(std::shared_ptr< DependencyCollector > Listener)
FrontendOptions & getFrontendOpts()
HeaderSearchOptions & getHeaderSearchOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
DiagnosticOptions & getDiagnosticOpts()
LangOptions & getLangOpts()
void setDependencyDirectivesGetter(std::unique_ptr< DependencyDirectivesGetter > Getter)
Helper class for holding the data necessary to invoke the compiler.
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()
ArrayRef< std::string > getDependencies() const
Definition: Utils.h:69
Functor that returns the dependency directives for a given file.
virtual std::optional< ArrayRef< dependency_directives_scan::Directive > > operator()(FileEntryRef File)=0
Get the dependency directives for the given file.
virtual std::unique_ptr< DependencyDirectivesGetter > cloneFor(FileManager &FileMgr)=0
Clone the getter for a new FileManager instance.
Builds a dependency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
Definition: Utils.h:104
void finishedMainFile(DiagnosticsEngine &Diags) override
Called when the end of the main file is reached.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1722
virtual void finish()
Callback to inform the diagnostic client that processing of all source files has ended.
Definition: Diagnostic.h:1758
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:231
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1529
bool hasErrorOccurred() const
Definition: Diagnostic.h:871
DiagnosticConsumer * getClient()
Definition: Diagnostic.h:606
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition: FileEntry.h:57
Implements support for file system lookup, file system caching, and directory search management.
Definition: FileManager.h:53
llvm::vfs::FileSystem & getVirtualFileSystem() const
Definition: FileManager.h:219
unsigned ModulesShareFileManager
Whether to share the FileManager when building modules.
std::string OutputFile
The output file, if any.
unsigned GenerateGlobalModuleIndex
Whether we can generate the global module index if needed.
unsigned DisableFree
Disable memory freeing on exit.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
unsigned UseGlobalModuleIndex
Whether we can use the global module index if available.
HeaderSearchOptions - Helper class for storing options related to the initialization of the HeaderSea...
unsigned ModulesStrictContextHash
Whether we should include all things that could impact the module in the hash.
unsigned ModulesForceValidateUserHeaders
Whether to force the validation of user input files when a module is loaded (even despite the build s...
std::map< std::string, std::string, std::less<> > PrebuiltModuleFiles
The mapping of module names to prebuilt module files.
uint64_t BuildSessionTimestamp
The time in seconds when the build session started.
unsigned ModulesSkipHeaderSearchPaths
Whether to entirely skip writing header search paths.
std::string ModuleFormat
The module/pch container format.
std::string Sysroot
If non-empty, the directory to use as a "virtual system root" for include paths.
unsigned ModulesSkipDiagnosticOptions
Whether to entirely skip writing diagnostic options.
std::string ModuleCachePath
The directory used for the module cache.
std::vector< std::string > VFSOverlayFiles
The set of user-provided virtual filesystem overlay files.
unsigned ModulesSerializeOnlyPreprocessor
Whether AST files should only contain the preprocessor information.
unsigned ModulesSkipPragmaDiagnosticMappings
Whether to entirely skip writing pragma diagnostic mappings.
unsigned ModulesIncludeVFSUsage
Whether to include ivfsoverlay usage information in written AST files.
std::string ResourceDir
The directory which holds the compiler resource files (builtin includes, etc.).
unsigned ModulesValidateOncePerBuildSession
If true, skip verifying input files used by modules if the module was already verified during this bu...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:434
void setBuildingModule(bool BuildingModuleFlag)
Flag indicating whether this instance is building a module.
Definition: ModuleLoader.h:99
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
bool ModulesCheckRelocated
Perform extra checks when loading PCM files for mutable file systems.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
bool AllowPCHWithDifferentModulesCachePath
When true, a PCH with modules cache path different to the current compilation will not be rejected.
std::vector< std::pair< std::string, bool > > Macros
The base class of the type hierarchy.
Definition: TypeBase.h:1833
Command - An executable path/name and argument vector to execute.
Definition: Job.h:106
Dependency scanner callbacks that are used during scanning to influence the behaviour of the scan - f...
The dependency scanning service contains shared configuration and state that is used by the individua...
DependencyScanningFilesystemSharedCache & getSharedCache()
A virtual file system optimized for the dependency discovery.
void setBypassedPathPrefix(StringRef Prefix)
Set the prefix for paths that should bypass this VFS and go straight to the underlying VFS.
void resetBypassedPathPrefix()
Make it so that no paths bypass this VFS.
std::optional< ArrayRef< dependency_directives_scan::Directive > > getDirectiveTokens(const Twine &Path)
bool computeDependencies(StringRef WorkingDirectory, const std::vector< std::string > &CommandLine, DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, std::optional< llvm::MemoryBufferRef > TUBuffer=std::nullopt)
Run the dependency scanning tool for a given clang driver command-line, and report the discovered dep...
DependencyScanningWorker(DependencyScanningService &Service, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Construct a dependency scanning worker.
void setVFS(llvm::StringSet<> &&VFS)
Update the VFSMap to the one discovered from serializing the AST file.
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.
bool isInStableDir() const
Read-only access to whether the module is made up of dependencies in stable directories.
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
Definition: Driver.cpp:7143
llvm::Error expandResponseFiles(SmallVectorImpl< const char * > &Args, bool ClangCLMode, llvm::BumpPtrAllocator &Alloc, llvm::vfs::FileSystem *FS=nullptr)
Expand response files from a clang driver or cc1 invocation.
Definition: Driver.cpp:7160
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition: Driver.cpp:7158
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:43
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition: ModuleFile.h:48
@ DependencyDirectivesScan
This mode is used to compute the dependencies by running the preprocessor with special kind of lexing...
@ CanonicalPreprocessing
This mode is used to compute the dependencies by running the preprocessor over the source files.
bool areOptionsInStableDir(const ArrayRef< StringRef > Directories, const HeaderSearchOptions &HSOpts)
Determine if options collected from a module's compilation can safely be considered as stable.
IntrusiveRefCntPtr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries)
bool isPathInStableDir(const ArrayRef< StringRef > Directories, const StringRef Input)
Determine if Input can be resolved within a stable directory.
llvm::StringMap< PrebuiltModuleASTAttrs > PrebuiltModulesAttrsMap
Attributes loaded from AST files of prebuilt modules collected prior to ModuleDepCollector creation.
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.
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.