clang 23.0.0git
ModulesDriver.cpp
Go to the documentation of this file.
1//===--- ModulesDriver.cpp - Driver managed module builds -----------------===//
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///
9/// \file
10/// This file defines functionality to support driver managed builds for
11/// compilations which use Clang modules or standard C++20 named modules.
12///
13//===----------------------------------------------------------------------===//
14
17#include "clang/Basic/LLVM.h"
20#include "clang/Driver/Driver.h"
21#include "clang/Driver/Job.h"
22#include "clang/Driver/Tool.h"
25#include "llvm/ADT/DenseSet.h"
26#include "llvm/ADT/DepthFirstIterator.h"
27#include "llvm/ADT/DirectedGraph.h"
28#include "llvm/ADT/PostOrderIterator.h"
29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/SmallVectorExtras.h"
31#include "llvm/ADT/TypeSwitch.h"
32#include "llvm/ADT/iterator_range.h"
33#include "llvm/Option/ArgList.h"
34#include "llvm/Support/Casting.h"
35#include "llvm/Support/GraphWriter.h"
36#include "llvm/Support/JSON.h"
37#include "llvm/Support/Path.h"
38#include "llvm/Support/PrettyStackTrace.h"
39#include "llvm/Support/ThreadPool.h"
40#include "llvm/Support/VirtualFileSystem.h"
41#include <utility>
42
43namespace deps = clang::dependencies;
44
45using namespace llvm::opt;
46using namespace clang;
47using namespace driver;
48using namespace modules;
49
50namespace clang::driver::modules {
51static bool fromJSON(const llvm::json::Value &Params,
53 llvm::json::Path P) {
54 llvm::json::ObjectMapper O(Params, P);
55 return O.mapOptional("system-include-directories",
56 LocalArgs.SystemIncludeDirs);
57}
58
59static bool fromJSON(const llvm::json::Value &Params,
60 StdModuleManifest::Module &ModuleEntry,
61 llvm::json::Path P) {
62 llvm::json::ObjectMapper O(Params, P);
63 return O.map("is-std-library", ModuleEntry.IsStdlib) &&
64 O.map("logical-name", ModuleEntry.LogicalName) &&
65 O.map("source-path", ModuleEntry.SourcePath) &&
66 O.mapOptional("local-arguments", ModuleEntry.LocalArgs);
67}
68
69static bool fromJSON(const llvm::json::Value &Params,
70 StdModuleManifest &Manifest, llvm::json::Path P) {
71 llvm::json::ObjectMapper O(Params, P);
72 return O.map("modules", Manifest.Modules);
73}
74} // namespace clang::driver::modules
75
76/// Parses the Standard library module manifest from \p Buffer.
78 auto ParsedOrErr = llvm::json::parse(Buffer);
79 if (!ParsedOrErr)
80 return ParsedOrErr.takeError();
81
82 StdModuleManifest Manifest;
83 llvm::json::Path::Root Root;
84 if (!fromJSON(*ParsedOrErr, Manifest, Root))
85 return Root.getError();
86
87 return Manifest;
88}
89
90/// Converts each file path in manifest from relative to absolute.
91///
92/// Each file path in the manifest is expected to be relative the manifest's
93/// location \p ManifestPath itself.
96 StringRef ManifestPath) {
97 StringRef ManifestDir = llvm::sys::path::parent_path(ManifestPath);
98 SmallString<256> TempPath;
99
100 auto PrependManifestDir = [&](StringRef Path) {
101 TempPath = ManifestDir;
102 llvm::sys::path::append(TempPath, Path);
103 return std::string(TempPath);
104 };
105
106 for (auto &Entry : ManifestEntries) {
107 Entry.SourcePath = PrependManifestDir(Entry.SourcePath);
108 if (!Entry.LocalArgs)
109 continue;
110
111 for (auto &IncludeDir : Entry.LocalArgs->SystemIncludeDirs)
112 IncludeDir = PrependManifestDir(IncludeDir);
113 }
114}
115
117driver::modules::readStdModuleManifest(StringRef ManifestPath,
118 llvm::vfs::FileSystem &VFS) {
119 auto MemBufOrErr = VFS.getBufferForFile(ManifestPath);
120 if (!MemBufOrErr)
121 return llvm::createFileError(ManifestPath, MemBufOrErr.getError());
122
123 auto ManifestOrErr = parseManifest((*MemBufOrErr)->getBuffer());
124 if (!ManifestOrErr)
125 return ManifestOrErr.takeError();
126 auto Manifest = std::move(*ManifestOrErr);
127
128 makeManifestPathsAbsolute(Manifest.Modules, ManifestPath);
129 return Manifest;
130}
131
134 InputList &Inputs) {
135 DerivedArgList &Args = C.getArgs();
136 const OptTable &Opts = C.getDriver().getOpts();
137 for (const auto &Entry : ManifestEntries) {
138 auto *InputArg =
139 makeInputArg(Args, Opts, Args.MakeArgString(Entry.SourcePath));
140 Inputs.emplace_back(types::TY_CXXModule, InputArg);
141 }
142}
143
145 llvm::DenseMap<StringRef, const StdModuleManifest::Module *>;
146
147/// Builds a mapping from a module's source path to its entry in the manifest.
150 ManifestEntryLookup ManifestEntryBySource;
151 for (auto &Entry : ManifestEntries) {
152 [[maybe_unused]] const bool Inserted =
153 ManifestEntryBySource.try_emplace(Entry.SourcePath, &Entry).second;
154 assert(Inserted &&
155 "Manifest defines multiple modules with the same source path.");
156 }
157 return ManifestEntryBySource;
158}
159
160/// Returns the manifest entry corresponding to \p Job, or \c nullptr if none
161/// exists.
162static const StdModuleManifest::Module *
164 const ManifestEntryLookup &ManifestEntryBySource) {
165 for (const auto &II : Job.getInputInfos()) {
166 if (const auto It = ManifestEntryBySource.find(II.getFilename());
167 It != ManifestEntryBySource.end())
168 return It->second;
169 }
170 return nullptr;
171}
172
173/// Adds all \p SystemIncludeDirs to the \p CC1Args of \p Job.
174static void
176 ArgStringList &CC1Args,
177 ArrayRef<std::string> SystemIncludeDirs) {
178 const ToolChain &TC = Job.getCreator().getToolChain();
179 const DerivedArgList &TCArgs =
180 C.getArgsForToolChain(&TC, Job.getSource().getOffloadingArch(),
182
183 for (const auto &IncludeDir : SystemIncludeDirs)
184 TC.addSystemInclude(TCArgs, CC1Args, IncludeDir);
185}
186
187static bool isCC1Job(const Command &Job) {
188 return StringRef(Job.getCreator().getName()) == "clang";
189}
190
191/// Apply command-line modifications specific for inputs originating from the
192/// Standard library module manifest.
194 Compilation &C, const ManifestEntryLookup &ManifestEntryBySource,
195 MutableArrayRef<std::unique_ptr<Command>> Jobs) {
196 for (auto &Job : Jobs) {
197 if (!isCC1Job(*Job))
198 continue;
199
200 const auto *Entry = getManifestEntryForCommand(*Job, ManifestEntryBySource);
201 if (!Entry)
202 continue;
203
204 auto CC1Args = Job->getArguments();
205 if (Entry->IsStdlib)
206 CC1Args.push_back("-Wno-reserved-module-identifier");
207 if (Entry->LocalArgs)
208 addSystemIncludeDirsFromManifest(C, *Job, CC1Args,
209 Entry->LocalArgs->SystemIncludeDirs);
210 Job->replaceArguments(CC1Args);
211 }
212}
213
214/// Computes the -fmodule-cache-path for this compilation.
215static std::optional<std::string>
216getModuleCachePath(llvm::opt::DerivedArgList &Args) {
217 if (const Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
218 return A->getValue();
219
221 return std::string(Path);
222
223 return std::nullopt;
224}
225
226/// Returns true if a dependency scan can be performed using \p Job.
227static bool isDependencyScannableJob(const Command &Job) {
228 if (!isCC1Job(Job))
229 return false;
230 const auto &InputInfos = Job.getInputInfos();
231 return !InputInfos.empty() && types::isSrcFile(InputInfos.front().getType());
232}
233
234namespace {
235/// Pool of reusable dependency scanning workers and their contexts with
236/// RAII-based acquire/release.
237class ScanningWorkerPool {
238public:
239 ScanningWorkerPool(size_t NumWorkers,
240 deps::DependencyScanningService &ScanningService) {
241 for (size_t I = 0; I < NumWorkers; ++I)
242 Slots.emplace_back(ScanningService);
243
244 AvailableSlots.resize(NumWorkers);
245 std::iota(AvailableSlots.begin(), AvailableSlots.end(), 0);
246 }
247
248 /// Acquires a unique pointer to a dependency scanning worker and its
249 /// context.
250 ///
251 /// The worker bundle automatically released back to the pool when the
252 /// pointer is destroyed. The pool has to outlive the leased worker bundle.
253 [[nodiscard]] auto scopedAcquire() {
254 std::unique_lock<std::mutex> UL(Lock);
255 CV.wait(UL, [&] { return !AvailableSlots.empty(); });
256 const size_t Index = AvailableSlots.pop_back_val();
257 auto ReleaseHandle = [this, Index](WorkerBundle *) { release(Index); };
258 return std::unique_ptr<WorkerBundle, decltype(ReleaseHandle)>(
259 &Slots[Index], ReleaseHandle);
260 }
261
262private:
263 /// Releases the worker bundle at \c Index back into the pool.
264 void release(size_t Index) {
265 {
266 std::scoped_lock<std::mutex> SL(Lock);
267 AvailableSlots.push_back(Index);
268 }
269 CV.notify_one();
270 }
271
272 /// A scanning worker with its associated context.
273 struct WorkerBundle {
274 WorkerBundle(deps::DependencyScanningService &ScanningService)
275 : Worker(std::make_unique<deps::DependencyScanningWorker>(
276 ScanningService)) {}
277
278 std::unique_ptr<deps::DependencyScanningWorker> Worker;
279 llvm::DenseSet<deps::ModuleID> SeenModules;
280 };
281
282 std::mutex Lock;
283 std::condition_variable CV;
284 SmallVector<size_t> AvailableSlots;
285 SmallVector<WorkerBundle, 0> Slots;
286};
287} // anonymous namespace
288
289// Creates a ThreadPool and a corresponding ScanningWorkerPool optimized for
290// the configuration of dependency scan inputs.
291static std::pair<std::unique_ptr<llvm::ThreadPoolInterface>,
292 std::unique_ptr<ScanningWorkerPool>>
294 size_t NumScanInputs, bool HasStdlibModuleInputs,
295 deps::DependencyScanningService &ScanningService) {
296 // TODO: Benchmark: Determine the optimal number of worker threads for a
297 // given number of inputs. How many inputs are required for multi-threading
298 // to be beneficial? How many inputs should each thread scan at least?
299#if LLVM_ENABLE_THREADS
300 std::unique_ptr<llvm::ThreadPoolInterface> ThreadPool;
301 size_t WorkerCount;
302
303 if (NumScanInputs == 1 || (HasStdlibModuleInputs && NumScanInputs <= 2)) {
304 auto S = llvm::optimal_concurrency(1);
305 ThreadPool = std::make_unique<llvm::SingleThreadExecutor>(std::move(S));
306 WorkerCount = 1;
307 } else {
308 auto ThreadPoolStrategy = llvm::optimal_concurrency(
309 NumScanInputs - static_cast<size_t>(HasStdlibModuleInputs));
310 ThreadPool = std::make_unique<llvm::DefaultThreadPool>(
311 std::move(ThreadPoolStrategy));
312 const size_t MaxConcurrency = ThreadPool->getMaxConcurrency();
313 const size_t MaxConcurrentlyScannedInputs =
314 NumScanInputs -
315 (HasStdlibModuleInputs && NumScanInputs < MaxConcurrency ? 1 : 0);
316 WorkerCount = std::min(MaxConcurrency, MaxConcurrentlyScannedInputs);
317 }
318#else
319 auto ThreadPool = std::make_unique<llvm::SingleThreadExecutor>();
320 size_t WorkerCount = 1;
321#endif
322
323 return {std::move(ThreadPool),
324 std::make_unique<ScanningWorkerPool>(WorkerCount, ScanningService)};
325}
326
327static StringRef getTriple(const Command &Job) {
328 return Job.getCreator().getToolChain().getTriple().getTriple();
329}
330
331using ModuleNameAndTriple = std::pair<StringRef, StringRef>;
332
333namespace {
334/// Helper to schedule on-demand dependency scans for modules originating from
335/// the Standard library module manifest.
336struct StdlibModuleScanScheduler {
337 StdlibModuleScanScheduler(const llvm::DenseMap<ModuleNameAndTriple, size_t>
338 &StdlibModuleScanIndexByID)
339 : StdlibModuleScanIndexByID(StdlibModuleScanIndexByID) {
340 ScheduledScanInputs.reserve(StdlibModuleScanIndexByID.size());
341 }
342
343 /// Returns the indices of scan inputs corresponding to newly imported
344 /// Standard library modules.
345 ///
346 /// Thread-safe.
347 SmallVector<size_t, 2> getNewScanInputs(ArrayRef<std::string> NamedModuleDeps,
348 StringRef Triple) {
349 SmallVector<size_t, 2> NewScanInputs;
350 std::scoped_lock<std::mutex> Guard(Lock);
351 for (const auto &ModuleName : NamedModuleDeps) {
352 const auto It = StdlibModuleScanIndexByID.find({ModuleName, Triple});
353 if (It == StdlibModuleScanIndexByID.end())
354 continue;
355 const size_t ScanIndex = It->second;
356 const bool AlreadyScheduled =
357 !ScheduledScanInputs.insert(ScanIndex).second;
358 if (AlreadyScheduled)
359 continue;
360 NewScanInputs.push_back(ScanIndex);
361 }
362 return NewScanInputs;
363 }
364
365private:
366 const llvm::DenseMap<ModuleNameAndTriple, size_t> &StdlibModuleScanIndexByID;
367 llvm::SmallDenseSet<size_t> ScheduledScanInputs;
368 std::mutex Lock;
369};
370
371/// Collects diagnostics in a form that can be retained until after their
372/// associated SourceManager is destroyed.
373class StandaloneDiagCollector : public DiagnosticConsumer {
374public:
375 void BeginSourceFile(const LangOptions &LangOpts,
376 const Preprocessor *PP = nullptr) override {
377 this->LangOpts = &LangOpts;
378 }
379
380 void HandleDiagnostic(DiagnosticsEngine::Level Level,
381 const Diagnostic &Info) override {
382 StoredDiagnostic StoredDiag(Level, Info);
383 StandaloneDiags.emplace_back(*LangOpts, StoredDiag);
385 }
386
387 SmallVector<StandaloneDiagnostic, 0> takeDiagnostics() {
388 return std::move(StandaloneDiags);
389 }
390
391private:
392 const LangOptions *LangOpts = nullptr;
394};
395
396/// RAII utility to report collected StandaloneDiagnostic through a
397/// DiagnosticsEngine.
398///
399/// The driver's DiagnosticsEngine usually does not have a SourceManager at
400/// this point of building the compilation, in which case the
401/// StandaloneDiagReporter supplies its own.
402class StandaloneDiagReporter {
403public:
404 explicit StandaloneDiagReporter(DiagnosticsEngine &Diags) : Diags(Diags) {
405 if (!Diags.hasSourceManager()) {
407 Opts.WorkingDir = ".";
408 OwnedFileMgr = llvm::makeIntrusiveRefCnt<FileManager>(std::move(Opts));
409 OwnedSrcMgr =
410 llvm::makeIntrusiveRefCnt<SourceManager>(Diags, *OwnedFileMgr);
411 }
412 }
413
414 /// Emits all diagnostics in \c StandaloneDiags using the associated
415 /// DiagnosticsEngine.
416 void Report(ArrayRef<StandaloneDiagnostic> StandaloneDiags) const {
417 llvm::StringMap<SourceLocation> SrcLocCache;
418 Diags.getClient()->BeginSourceFile(LangOptions(), nullptr);
419 for (const auto &StandaloneDiag : StandaloneDiags) {
420 const auto StoredDiag = translateStandaloneDiag(
421 getFileManager(), getSourceManager(), StandaloneDiag, SrcLocCache);
422 Diags.Report(StoredDiag);
423 }
424 Diags.getClient()->EndSourceFile();
425 }
426
427private:
428 DiagnosticsEngine &Diags;
431
432 FileManager &getFileManager() const {
433 if (OwnedFileMgr)
434 return *OwnedFileMgr;
435 return Diags.getSourceManager().getFileManager();
436 }
437
438 SourceManager &getSourceManager() const {
439 if (OwnedSrcMgr)
440 return *OwnedSrcMgr;
441 return Diags.getSourceManager();
442 }
443};
444} // anonymous namespace
445
446/// Report the diagnostics collected during each dependency scan.
449 DiagnosticsEngine &Diags) {
450 StandaloneDiagReporter Reporter(Diags);
451 for (auto &SingleScanDiags : AllScanDiags)
452 Reporter.Report(SingleScanDiags);
453}
454
455/// Construct a path for the explicitly built PCM.
456static std::string constructPCMPath(const deps::ModuleID &ID,
457 StringRef OutputDir) {
458 assert(!ID.ModuleName.empty() && !ID.ContextHash.empty() &&
459 "Invalid ModuleID!");
460 SmallString<256> ExplicitPCMPath(OutputDir);
461 llvm::sys::path::append(ExplicitPCMPath, ID.ContextHash,
462 ID.ModuleName + "-" + ID.ContextHash + ".pcm");
463 return std::string(ExplicitPCMPath);
464}
465
466namespace {
467/// A simple dependency action controller that only provides module lookup for
468/// Clang modules.
469class ModuleLookupController : public deps::DependencyActionController {
470public:
471 ModuleLookupController(StringRef OutputDir) : OutputDir(OutputDir) {}
472
473 std::string lookupModuleOutput(const deps::ModuleDeps &MD,
474 deps::ModuleOutputKind Kind) override {
476 return constructPCMPath(MD.ID, OutputDir);
477
478 // Driver command lines that trigger lookups for unsupported
479 // ModuleOutputKinds are not supported by the modules driver. Those
480 // command lines should probably be adjusted or rejected in
481 // Driver::handleArguments or Driver::HandleImmediateArgs.
482 llvm::reportFatalInternalError(
483 "call to lookupModuleOutput with unexpected ModuleOutputKind");
484 }
485
486 std::unique_ptr<DependencyActionController> clone() const override {
487 return std::make_unique<ModuleLookupController>(OutputDir);
488 }
489
490private:
491 StringRef OutputDir;
492};
493
494/// The full dependencies for a specific command-line input.
495struct InputDependencies {
496 /// The name of the C++20 module provided by this translation unit.
497 std::string ModuleName;
498
499 /// A list of modules this translation unit directly depends on, not including
500 /// transitive dependencies.
501 ///
502 /// This may include modules with a different context hash when it can be
503 /// determined that the differences are benign for this compilation.
504 std::vector<deps::ModuleID> ClangModuleDeps;
505
506 /// A list of the C++20 named modules this translation unit depends on.
507 ///
508 /// These correspond only to modules built with compatible compiler
509 /// invocations.
510 std::vector<std::string> NamedModuleDeps;
511
512 /// A collection of absolute paths to files that this translation unit
513 /// directly depends on, not including transitive dependencies.
514 std::vector<std::string> FileDeps;
515
516 /// The compiler invocation with modifications to properly import all Clang
517 /// module dependencies. Does not include argv[0].
518 std::vector<std::string> BuildArgs;
519};
520} // anonymous namespace
521
522static InputDependencies makeInputDeps(deps::TranslationUnitDeps &&TUDeps) {
523 InputDependencies InputDeps;
524 InputDeps.ModuleName = std::move(TUDeps.ID.ModuleName);
525 InputDeps.NamedModuleDeps = std::move(TUDeps.NamedModuleDeps);
526 InputDeps.ClangModuleDeps = std::move(TUDeps.ClangModuleDeps);
527 InputDeps.FileDeps = std::move(TUDeps.FileDeps);
528 assert(TUDeps.Commands.size() == 1 && "Expected exactly one command");
529 InputDeps.BuildArgs = std::move(TUDeps.Commands.front().Arguments);
530 return InputDeps;
531}
532
533/// Constructs the full command line, including the executable, for \p Job.
535 const auto &JobArgs = Job.getArguments();
536 SmallVector<std::string, 0> CommandLine;
537 CommandLine.reserve(JobArgs.size() + 1);
538 CommandLine.emplace_back(Job.getExecutable());
539 for (const char *Arg : JobArgs)
540 CommandLine.emplace_back(Arg);
541 return CommandLine;
542}
543
544/// Performs a dependency scan for a single job.
545///
546/// \returns a pair containing TranslationUnitDeps on success, or std::nullopt
547/// on failure, along with any diagnostics produced.
548static std::pair<std::optional<deps::TranslationUnitDeps>,
550scanDependenciesForJob(const Command &Job, ScanningWorkerPool &WorkerPool,
551 StringRef WorkingDirectory,
552 ModuleLookupController &LookupController) {
553 StandaloneDiagCollector DiagConsumer;
554 std::optional<deps::TranslationUnitDeps> MaybeTUDeps;
555
556 {
557 const auto CC1CommandLine = buildCommandLine(Job);
558 auto WorkerBundleHandle = WorkerPool.scopedAcquire();
559 deps::FullDependencyConsumer DepConsumer(WorkerBundleHandle->SeenModules);
560
561 if (WorkerBundleHandle->Worker->computeDependencies(
562 WorkingDirectory, CC1CommandLine, DepConsumer, LookupController,
563 DiagConsumer))
564 MaybeTUDeps = DepConsumer.takeTranslationUnitDeps();
565 }
566
567 return {std::move(MaybeTUDeps), DiagConsumer.takeDiagnostics()};
568}
569
570namespace {
571struct DependencyScanResult {
572 /// Indices of jobs that were successfully scanned.
573 SmallVector<size_t> ScannedJobIndices;
574
575 /// Input dependencies for scanned jobs. Parallel to \c ScannedJobIndices.
576 SmallVector<InputDependencies, 0> InputDepsForScannedJobs;
577
578 /// Module dependency graphs for scanned jobs. Parallel to \c
579 /// ScannedJobIndices.
580 SmallVector<deps::ModuleDepsGraph, 0> ModuleDepGraphsForScannedJobs;
581
582 /// Indices of Standard library module jobs not discovered as dependencies.
583 SmallVector<size_t> UnusedStdlibModuleJobIndices;
584
585 /// Indices of jobs that could not be scanned (e.g. image jobs, ...).
586 SmallVector<size_t> NonScannableJobIndices;
587};
588} // anonymous namespace
589
590/// Scans the compilations job list \p Jobs for module dependencies.
591///
592/// Standard library module jobs are scanned on demand if imported by any
593/// user-provided input.
594///
595/// \returns DependencyScanResult on success, or std::nullopt on failure, with
596/// diagnostics reported via \p Diags in both cases.
597static std::optional<DependencyScanResult> scanDependencies(
598 ArrayRef<std::unique_ptr<Command>> Jobs,
599 llvm::DenseMap<StringRef, const StdModuleManifest::Module *> ManifestLookup,
600 StringRef ModuleCachePath, StringRef WorkingDirectory,
601 DiagnosticsEngine &Diags) {
602 llvm::PrettyStackTraceString CrashInfo("Performing module dependency scan.");
603
604 // Classify the jobs based on scan eligibility.
605 SmallVector<size_t> ScannableJobIndices;
606 SmallVector<size_t> NonScannableJobIndices;
607 for (const auto &&[Index, Job] : llvm::enumerate(Jobs)) {
608 if (isDependencyScannableJob(*Job))
609 ScannableJobIndices.push_back(Index);
610 else
611 NonScannableJobIndices.push_back(Index);
612 }
613
614 // Classify scannable jobs by origin. User-provided inputs will be scanned
615 // immediately, while Standard library modules are indexed for on-demand
616 // scanning when discovered as dependencies.
617 SmallVector<size_t> UserInputScanIndices;
618 llvm::DenseMap<ModuleNameAndTriple, size_t> StdlibModuleScanIndexByID;
619 for (const auto &&[ScanIndex, JobIndex] :
620 llvm::enumerate(ScannableJobIndices)) {
621 const Command &ScanJob = *Jobs[JobIndex];
622 if (const auto *Entry =
623 getManifestEntryForCommand(ScanJob, ManifestLookup)) {
624 ModuleNameAndTriple ID{Entry->LogicalName, getTriple(ScanJob)};
625 [[maybe_unused]] const bool Inserted =
626 StdlibModuleScanIndexByID.try_emplace(ID, ScanIndex).second;
627 assert(Inserted &&
628 "Multiple jobs build the same module for the same triple.");
629 } else {
630 UserInputScanIndices.push_back(ScanIndex);
631 }
632 }
633
634 // Initialize the scan context.
635 const size_t NumScanInputs = ScannableJobIndices.size();
636 const bool HasStdlibModuleInputs = !StdlibModuleScanIndexByID.empty();
637
639 deps::DependencyScanningService ScanningService(std::move(Opts));
640
641 std::unique_ptr<llvm::ThreadPoolInterface> ThreadPool;
642 std::unique_ptr<ScanningWorkerPool> WorkerPool;
643 std::tie(ThreadPool, WorkerPool) = createOptimalThreadAndWorkerPool(
644 NumScanInputs, HasStdlibModuleInputs, ScanningService);
645
646 StdlibModuleScanScheduler StdlibModuleRegistry(StdlibModuleScanIndexByID);
647 ModuleLookupController LookupController(ModuleCachePath);
648
649 // Scan results are indexed by ScanIndex into ScannableJobIndices, not by
650 // JobIndex into Jobs. This allows one result slot per scannable job.
652 NumScanInputs);
654 NumScanInputs);
655 std::atomic<bool> HasError{false};
656
657 // Scans the job at the given scan index and schedules scans for any newly
658 // discovered Standard library module dependencies.
659 std::function<void(size_t)> ScanOneAndScheduleNew;
660 ScanOneAndScheduleNew = [&](size_t ScanIndex) {
661 const size_t JobIndex = ScannableJobIndices[ScanIndex];
662 const Command &Job = *Jobs[JobIndex];
663 auto [MaybeTUDeps, ScanDiags] = scanDependenciesForJob(
664 Job, *WorkerPool, WorkingDirectory, LookupController);
665
666 // Store diagnostics even for successful scans to also capture any warnings
667 // or notes.
668 assert(AllScanDiags[ScanIndex].empty() &&
669 "Each slot should be written to at most once.");
670 AllScanDiags[ScanIndex] = std::move(ScanDiags);
671
672 if (!MaybeTUDeps) {
673 HasError.store(true, std::memory_order_relaxed);
674 return;
675 }
676
677 // Schedule scans for newly discovered Standard library module dependencies.
678 const auto NewScanInputs = StdlibModuleRegistry.getNewScanInputs(
679 MaybeTUDeps->NamedModuleDeps, getTriple(Job));
680 for (const size_t NewScanIndex : NewScanInputs)
681 ThreadPool->async(
682 [&, NewScanIndex]() { ScanOneAndScheduleNew(NewScanIndex); });
683
684 assert(!AllScanResults[ScanIndex].has_value() &&
685 "Each slot should be written to at most once.");
686 AllScanResults[ScanIndex] = std::move(MaybeTUDeps);
687 };
688
689 // Initiate the scan with all jobs for user-provided inputs.
690 for (const size_t ScanIndex : UserInputScanIndices)
691 ThreadPool->async([&ScanOneAndScheduleNew, ScanIndex]() {
692 ScanOneAndScheduleNew(ScanIndex);
693 });
694 ThreadPool->wait();
695
696 reportAllScanDiagnostics(std::move(AllScanDiags), Diags);
697 if (HasError.load(std::memory_order_relaxed))
698 return std::nullopt;
699
700 // Collect results, mapping scan indices back to job indices.
701 DependencyScanResult Result;
702 for (auto &&[JobIndex, MaybeTUDeps] :
703 llvm::zip_equal(ScannableJobIndices, AllScanResults)) {
704 if (MaybeTUDeps) {
705 Result.ScannedJobIndices.push_back(JobIndex);
706 Result.ModuleDepGraphsForScannedJobs.push_back(
707 std::move(MaybeTUDeps->ModuleGraph));
708 Result.InputDepsForScannedJobs.push_back(
709 makeInputDeps(std::move(*MaybeTUDeps)));
710 } else
711 Result.UnusedStdlibModuleJobIndices.push_back(JobIndex);
712 }
713 Result.NonScannableJobIndices = std::move(NonScannableJobIndices);
714
715#ifndef NDEBUG
716 llvm::SmallDenseSet<size_t> SeenJobIndices;
717 SeenJobIndices.insert_range(Result.ScannedJobIndices);
718 SeenJobIndices.insert_range(Result.UnusedStdlibModuleJobIndices);
719 SeenJobIndices.insert_range(Result.NonScannableJobIndices);
720 assert(llvm::all_of(llvm::index_range(0, Jobs.size()),
721 [&](size_t JobIndex) {
722 return SeenJobIndices.contains(JobIndex);
723 }) &&
724 "Scan result must partition all jobs");
725#endif
726
727 return Result;
728}
729
730namespace {
731class CGNode;
732class CGEdge;
733using CGNodeBase = llvm::DGNode<CGNode, CGEdge>;
734using CGEdgeBase = llvm::DGEdge<CGNode, CGEdge>;
735using CGBase = llvm::DirectedGraph<CGNode, CGEdge>;
736
737/// Compilation Graph Node
738class CGNode : public CGNodeBase {
739public:
740 enum class NodeKind {
741 ClangModuleCC1Job,
742 NamedModuleCC1Job,
743 NonModuleCC1Job,
744 MiscJob,
745 ImageJob,
746 Root,
747 };
748
749 CGNode(const NodeKind K) : Kind(K) {}
750 CGNode(const CGNode &) = delete;
751 CGNode(CGNode &&) = delete;
752 virtual ~CGNode() = 0;
753
754 NodeKind getKind() const { return Kind; }
755
756private:
757 NodeKind Kind;
758};
759CGNode::~CGNode() = default;
760
761/// Subclass of CGNode representing the root node of the graph.
762///
763/// The root node is a special node that connects to all other nodes with
764/// no incoming edges, so that there is always a path from it to any node
765/// in the graph.
766///
767/// There should only be one such node in a given graph.
768class RootNode : public CGNode {
769public:
770 RootNode() : CGNode(NodeKind::Root) {}
771 ~RootNode() override = default;
772
773 static bool classof(const CGNode *N) {
774 return N->getKind() == NodeKind::Root;
775 }
776};
777
778/// Base class for any CGNode type that represents a job.
779class JobNode : public CGNode {
780public:
781 JobNode(std::unique_ptr<Command> &&Job, NodeKind Kind)
782 : CGNode(Kind), Job(std::move(Job)) {
783 assert(this->Job && "Expected valid job!");
784 }
785 virtual ~JobNode() override = 0;
786
787 std::unique_ptr<Command> Job;
788
789 static bool classof(const CGNode *N) {
790 return N->getKind() != NodeKind::Root;
791 }
792};
793JobNode::~JobNode() = default;
794
795/// Subclass of CGNode representing a -cc1 job which produces a Clang module.
796class ClangModuleJobNode : public JobNode {
797public:
798 ClangModuleJobNode(std::unique_ptr<Command> &&Job, deps::ModuleDeps &&MD)
799 : JobNode(std::move(Job), NodeKind::ClangModuleCC1Job),
800 MD(std::move(MD)) {}
801 ~ClangModuleJobNode() override = default;
802
803 deps::ModuleDeps MD;
804
805 static bool classof(const CGNode *N) {
806 return N->getKind() == NodeKind::ClangModuleCC1Job;
807 }
808};
809
810/// Base class for any CGNode type that represents any scanned -cc1 job.
811class ScannedJobNode : public JobNode {
812public:
813 ScannedJobNode(std::unique_ptr<Command> &&Job, InputDependencies &&InputDeps,
814 NodeKind Kind)
815 : JobNode(std::move(Job), Kind), InputDeps(std::move(InputDeps)) {}
816 ~ScannedJobNode() override = default;
817
818 InputDependencies InputDeps;
819
820 static bool classof(const CGNode *N) {
821 return N->getKind() == NodeKind::NamedModuleCC1Job ||
822 N->getKind() == NodeKind::NonModuleCC1Job;
823 }
824};
825
826/// Subclass of CGNode representing a -cc1 job which produces a C++20 named
827/// module.
828class NamedModuleJobNode : public ScannedJobNode {
829public:
830 NamedModuleJobNode(std::unique_ptr<Command> &&Job,
831 InputDependencies &&InputDeps)
832 : ScannedJobNode(std::move(Job), std::move(InputDeps),
833 NodeKind::NamedModuleCC1Job) {}
834 ~NamedModuleJobNode() override = default;
835
836 static bool classof(const CGNode *N) {
837 return N->getKind() == NodeKind::NamedModuleCC1Job;
838 }
839};
840
841/// Subclass of CGNode representing a -cc1 job which does not produce any
842/// module, but might still have module imports.
843class NonModuleTUJobNode : public ScannedJobNode {
844public:
845 NonModuleTUJobNode(std::unique_ptr<Command> &&Job,
846 InputDependencies &&InputDeps)
847 : ScannedJobNode(std::move(Job), std::move(InputDeps),
848 NodeKind::NonModuleCC1Job) {}
849 ~NonModuleTUJobNode() override = default;
850
851 static bool classof(const CGNode *N) {
852 return N->getKind() == NodeKind::NonModuleCC1Job;
853 }
854};
855
856/// Subclass of CGNode representing a job which produces an image file, such as
857/// a linker or interface stub merge job.
858class ImageJobNode : public JobNode {
859public:
860 ImageJobNode(std::unique_ptr<Command> &&Job)
861 : JobNode(std::move(Job), NodeKind::ImageJob) {}
862 ~ImageJobNode() override = default;
863
864 static bool classof(const CGNode *N) {
865 return N->getKind() == NodeKind::ImageJob;
866 }
867};
868
869/// Subclass of CGNode representing any job not covered by the other node types.
870///
871/// Jobs represented by this node type are not modified by the modules driver.
872class MiscJobNode : public JobNode {
873public:
874 MiscJobNode(std::unique_ptr<Command> &&Job)
875 : JobNode(std::move(Job), NodeKind::MiscJob) {}
876 ~MiscJobNode() override = default;
877
878 static bool classof(const CGNode *N) {
879 return N->getKind() == NodeKind::MiscJob;
880 }
881};
882
883/// Compilation Graph Edge
884///
885/// Edges connect the producer of an output to its consumer, except for edges
886/// stemming from the root node.
887class CGEdge : public CGEdgeBase {
888public:
889 enum class EdgeKind {
890 Regular,
891 ModuleDependency,
892 Rooted,
893 };
894
895 CGEdge(CGNode &N, EdgeKind K) : CGEdgeBase(N), Kind(K) {}
896
897 EdgeKind getKind() const { return Kind; }
898
899private:
900 EdgeKind Kind;
901};
902
903/// Compilation Graph
904///
905/// The graph owns all of its components.
906/// All nodes and edges created by the graph have the same livetime as the
907/// graph, even if removed from the graph's node list.
908class CompilationGraph : public CGBase {
909public:
910 CompilationGraph() = default;
911 CompilationGraph(const CompilationGraph &) = delete;
912 CompilationGraph(CompilationGraph &&G) = default;
913
914 CGNode &getRoot() const {
915 assert(Root && "Root node has not yet been created!");
916 return *Root;
917 }
918
919 RootNode &createRoot() {
920 assert(!Root && "Root node has already been created!");
921 auto &RootRef = createNodeImpl<RootNode>();
922 Root = &RootRef;
923 return RootRef;
924 }
925
926 template <typename T, typename... Args> T &createJobNode(Args &&...Arg) {
927 static_assert(std::is_base_of<JobNode, T>::value,
928 "T must be derived from JobNode");
929 return createNodeImpl<T>(std::forward<Args>(Arg)...);
930 }
931
932 CGEdge &createEdge(CGEdge::EdgeKind Kind, CGNode &Src, CGNode &Dst) {
933 auto Edge = std::make_unique<CGEdge>(Dst, Kind);
934 CGEdge &EdgeRef = *Edge;
935 AllEdges.push_back(std::move(Edge));
936 connect(Src, Dst, EdgeRef);
937 return EdgeRef;
938 }
939
940private:
941 using CGBase::addNode;
942 using CGBase::connect;
943
944 template <typename T, typename... Args> T &createNodeImpl(Args &&...Arg) {
945 auto Node = std::make_unique<T>(std::forward<Args>(Arg)...);
946 T &NodeRef = *Node;
947 AllNodes.push_back(std::move(Node));
948 addNode(NodeRef);
949 return NodeRef;
950 }
951
952 CGNode *Root = nullptr;
953 SmallVector<std::unique_ptr<CGNode>> AllNodes;
954 SmallVector<std::unique_ptr<CGEdge>> AllEdges;
955};
956} // anonymous namespace
957
958static StringRef getFirstInputFilename(const Command &Job) {
959 return Job.getInputInfos().front().getFilename();
960}
961
962namespace llvm {
963/// Non-const versions of the GraphTraits specializations for CompilationGraph.
964template <> struct GraphTraits<CGNode *> {
965 using NodeRef = CGNode *;
966
967 static NodeRef CGGetTargetNode(CGEdge *E) { return &E->getTargetNode(); }
968
970 mapped_iterator<CGNode::iterator, decltype(&CGGetTargetNode)>;
971 using ChildEdgeIteratorType = CGNode::iterator;
972
973 static NodeRef getEntryNode(NodeRef N) { return N; }
974
976 return ChildIteratorType(N->begin(), &CGGetTargetNode);
977 }
978
980 return ChildIteratorType(N->end(), &CGGetTargetNode);
981 }
982
984 return N->begin();
985 }
986 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
987};
988
989template <> struct GraphTraits<CompilationGraph *> : GraphTraits<CGNode *> {
990 using GraphRef = CompilationGraph *;
991 using NodeRef = CGNode *;
992
993 using nodes_iterator = CompilationGraph::iterator;
994
995 static NodeRef getEntryNode(GraphRef G) { return &G->getRoot(); }
996
997 static nodes_iterator nodes_begin(GraphRef G) { return G->begin(); }
998
999 static nodes_iterator nodes_end(GraphRef G) { return G->end(); }
1000};
1001
1002/// Const versions of the GraphTraits specializations for CompilationGraph.
1003template <> struct GraphTraits<const CGNode *> {
1004 using NodeRef = const CGNode *;
1005
1006 static NodeRef CGGetTargetNode(const CGEdge *E) {
1007 return &E->getTargetNode();
1008 }
1009
1011 mapped_iterator<CGNode::const_iterator, decltype(&CGGetTargetNode)>;
1012 using ChildEdgeIteratorType = CGNode::const_iterator;
1013
1014 static NodeRef getEntryNode(NodeRef N) { return N; }
1015
1017 return ChildIteratorType(N->begin(), &CGGetTargetNode);
1018 }
1019
1021 return ChildIteratorType(N->end(), &CGGetTargetNode);
1022 }
1023
1025 return N->begin();
1026 }
1027
1028 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
1029};
1030
1031template <>
1032struct GraphTraits<const CompilationGraph *> : GraphTraits<const CGNode *> {
1033 using GraphRef = const CompilationGraph *;
1034 using NodeRef = const CGNode *;
1035
1036 using nodes_iterator = CompilationGraph::const_iterator;
1037
1038 static NodeRef getEntryNode(GraphRef G) { return &G->getRoot(); }
1039
1040 static nodes_iterator nodes_begin(GraphRef G) { return G->begin(); }
1041
1042 static nodes_iterator nodes_end(GraphRef G) { return G->end(); }
1043};
1044
1045template <>
1046struct DOTGraphTraits<const CompilationGraph *> : DefaultDOTGraphTraits {
1047 explicit DOTGraphTraits(bool IsSimple = false)
1048 : DefaultDOTGraphTraits(IsSimple) {}
1049 using GraphRef = const CompilationGraph *;
1050 using NodeRef = const CGNode *;
1051
1052 static std::string getGraphName(GraphRef) {
1053 return "Module Dependency Graph";
1054 }
1055
1056 static std::string getGraphProperties(GraphRef) {
1057 return "\tnode [shape=Mrecord, colorscheme=set23, style=filled];\n";
1058 }
1059
1060 static bool renderGraphFromBottomUp() { return true; }
1061
1063 // Only show nodes with module dependency relations.
1065 }
1066
1067 static std::string getNodeIdentifier(NodeRef N, GraphRef) {
1068 return llvm::TypeSwitch<NodeRef, std::string>(N)
1069 .Case([](const ClangModuleJobNode *ClangModuleNode) {
1070 const auto &ID = ClangModuleNode->MD.ID;
1071 return llvm::formatv("{0}-{1}", ID.ModuleName, ID.ContextHash).str();
1072 })
1073 .Case([](const NamedModuleJobNode *NamedModuleNode) {
1074 return llvm::formatv("{0}-{1}", NamedModuleNode->InputDeps.ModuleName,
1075 getTriple(*NamedModuleNode->Job))
1076 .str();
1077 })
1078 .Case([](const NonModuleTUJobNode *NonModuleTUNode) {
1079 const auto &Job = *NonModuleTUNode->Job;
1080 return llvm::formatv("{0}-{1}", getFirstInputFilename(Job),
1081 getTriple(Job))
1082 .str();
1083 })
1084 .DefaultUnreachable("Unexpected node kind! Is this node hidden?");
1085 }
1086
1087 static std::string getNodeLabel(NodeRef N, GraphRef) {
1088 return llvm::TypeSwitch<NodeRef, std::string>(N)
1089 .Case([](const ClangModuleJobNode *ClangModuleNode) {
1090 const auto &ID = ClangModuleNode->MD.ID;
1091 return llvm::formatv("Module type: Clang module \\| Module name: {0} "
1092 "\\| Hash: {1}",
1093 ID.ModuleName, ID.ContextHash)
1094 .str();
1095 })
1096 .Case([](const NamedModuleJobNode *NamedModuleNode) {
1097 const auto &Job = *NamedModuleNode->Job;
1098 return llvm::formatv(
1099 "Filename: {0} \\| Module type: Named module \\| "
1100 "Module name: {1} \\| Triple: {2}",
1102 NamedModuleNode->InputDeps.ModuleName, getTriple(Job))
1103 .str();
1104 })
1105 .Case([](const NonModuleTUJobNode *NonModuleTUNode) {
1106 const auto &Job = *NonModuleTUNode->Job;
1107 return llvm::formatv("Filename: {0} \\| Triple: {1}",
1109 .str();
1110 })
1111 .DefaultUnreachable("Unexpected node kind! Is this node hidden?");
1112 }
1113
1114 static std::string getNodeAttributes(NodeRef N, GraphRef) {
1115 switch (N->getKind()) {
1116 case CGNode::NodeKind::ClangModuleCC1Job:
1117 return "fillcolor=1";
1118 case CGNode::NodeKind::NamedModuleCC1Job:
1119 return "fillcolor=2";
1120 case CGNode::NodeKind::NonModuleCC1Job:
1121 return "fillcolor=3";
1122 default:
1123 llvm_unreachable("Unexpected node kind! Is this node hidden?");
1124 }
1125 }
1126};
1127
1128/// GraphWriter specialization for CompilationGraph that emits a more
1129/// human-readable DOT graph.
1130template <>
1131class GraphWriter<const CompilationGraph *>
1132 : public GraphWriterBase<const CompilationGraph *,
1134public:
1135 using GraphType = const CompilationGraph *;
1137
1138 GraphWriter(llvm::raw_ostream &O, const GraphType &G, bool IsSimple)
1139 : Base(O, G, IsSimple), EscapedIDByNodeRef(G->size()) {}
1140
1141 void writeNodes() {
1142 auto IsNodeVisible = [&](NodeRef N) { return !DTraits.isNodeHidden(N, G); };
1143 auto VisibleNodes = llvm::filter_to_vector(nodes(G), IsNodeVisible);
1144
1145 writeNodeDefinitions(VisibleNodes);
1146 O << "\n";
1147 writeNodeRelations(VisibleNodes);
1148 }
1149
1150private:
1151 using Base::DOTTraits;
1152 using Base::GTraits;
1153 using Base::NodeRef;
1154
1155 void writeNodeDefinitions(ArrayRef<NodeRef> VisibleNodes) {
1156 for (NodeRef Node : VisibleNodes) {
1157 std::string EscapedNodeID =
1158 DOT::EscapeString(DTraits.getNodeIdentifier(Node, G));
1159 const std::string NodeLabel = DTraits.getNodeLabel(Node, G);
1160 const std::string NodeAttrs = DTraits.getNodeAttributes(Node, G);
1161 O << '\t' << '"' << EscapedNodeID << "\" [" << NodeAttrs << ", label=\"{ "
1162 << DOT::EscapeString(NodeLabel) << " }\"];\n";
1163 EscapedIDByNodeRef.try_emplace(Node, std::move(EscapedNodeID));
1164 }
1165 }
1166
1167 void writeNodeRelations(ArrayRef<NodeRef> VisibleNodes) {
1168 auto IsNodeVisible = [&](NodeRef N) { return !DTraits.isNodeHidden(N, G); };
1169 for (NodeRef Node : VisibleNodes) {
1170 auto DstNodes = llvm::make_range(GTraits::child_begin(Node),
1171 GTraits::child_end(Node));
1172 auto VisibleDstNodes = llvm::make_filter_range(DstNodes, IsNodeVisible);
1173 StringRef EscapedSrcNodeID = EscapedIDByNodeRef.at(Node);
1174 for (NodeRef DstNode : VisibleDstNodes) {
1175 StringRef EscapedTgtNodeID = EscapedIDByNodeRef.at(DstNode);
1176 O << '\t' << '"' << EscapedSrcNodeID << "\" -> \"" << EscapedTgtNodeID
1177 << "\";\n";
1178 }
1179 }
1180 }
1181
1182 DenseMap<NodeRef, std::string> EscapedIDByNodeRef;
1183};
1184} // namespace llvm
1185
1187takeJobsAtIndices(SmallVectorImpl<std::unique_ptr<Command>> &Jobs,
1188 ArrayRef<size_t> Indices) {
1190 for (const auto JobIndex : Indices) {
1191 assert(Jobs[JobIndex] && "Expected valid job!");
1192 Out.push_back(std::move(Jobs[JobIndex]));
1193 }
1194 return Out;
1195}
1196
1197/// Creates nodes for all jobs that could not be scanned (e.g. image jobs, ...).
1199 CompilationGraph &Graph,
1200 SmallVectorImpl<std::unique_ptr<Command>> &&NonScannableJobs) {
1201 for (auto &Job : NonScannableJobs) {
1202 if (Job->getCreator().isLinkJob())
1203 Graph.createJobNode<ImageJobNode>(std::move(Job));
1204 else
1205 Graph.createJobNode<MiscJobNode>(std::move(Job));
1206 }
1207}
1208
1209/// Creates nodes for the Standard library module jobs not discovered as
1210/// dependencies.
1211///
1212/// These and any dependent (non-image) job nodes should be pruned from the
1213/// graph later.
1215 CompilationGraph &Graph,
1216 SmallVectorImpl<std::unique_ptr<Command>> &&UnusedStdlibModuleJobs) {
1217 SmallVector<JobNode *> StdlibModuleNodesToPrune;
1218 for (auto &Job : UnusedStdlibModuleJobs) {
1219 auto &NewNode = Graph.createJobNode<MiscJobNode>(std::move(Job));
1220 StdlibModuleNodesToPrune.push_back(&NewNode);
1221 }
1222 return StdlibModuleNodesToPrune;
1223}
1224
1225/// Creates a job for the Clang module described by \p MD.
1226static std::unique_ptr<CC1Command>
1228 const deps::ModuleDeps &MD) {
1229 DerivedArgList &Args = C.getArgs();
1230 const OptTable &Opts = C.getDriver().getOpts();
1231 Arg *InputArg = makeInputArg(Args, Opts, "<discovered clang module>");
1232 Action *IA = C.MakeAction<InputAction>(*InputArg, types::ID::TY_ModuleFile);
1233 Action *PA = C.MakeAction<PrecompileJobAction>(IA, types::ID::TY_ModuleFile);
1234 PA->propagateOffloadInfo(&ImportingJob.getSource());
1235
1236 const auto &TC = ImportingJob.getCreator().getToolChain();
1237 const auto &TCArgs = C.getArgsForToolChain(&TC, PA->getOffloadingArch(),
1238 PA->getOffloadingDeviceKind());
1239
1240 const auto &BuildArgs = MD.getBuildArguments();
1241 ArgStringList JobArgs;
1242 JobArgs.reserve(BuildArgs.size());
1243 for (const auto &Arg : BuildArgs)
1244 JobArgs.push_back(TCArgs.MakeArgString(Arg));
1245
1246 return std::make_unique<CC1Command>(
1247 *PA, ImportingJob.getCreator(), ResponseFileSupport::AtFileUTF8(),
1248 C.getDriver().getClangProgramPath(), JobArgs,
1249 /*Inputs=*/ArrayRef<InputInfo>{},
1250 /*Outputs=*/ArrayRef<InputInfo>{});
1251}
1252
1253/// Creates a \c ClangModuleJobNode with associated job for each unique Clang
1254/// module in \p ModuleDepGraphsForScannedJobs.
1255///
1256/// \param ImportingJobs Jobs whose module dependencies were scanned.
1257/// \param ModuleDepGraphsForScannedJobs Full Clang module dependency graphs
1258/// corresponding to \p ImportingJobs, in order.
1260 CompilationGraph &Graph, Compilation &C,
1261 ArrayRef<std::unique_ptr<Command>> ImportingJobs,
1262 SmallVectorImpl<deps::ModuleDepsGraph> &&ModuleDepGraphsForScannedJobs) {
1263 llvm::DenseSet<deps::ModuleID> AlreadySeen;
1264 for (auto &&[ImportingJob, ModuleDepsGraph] :
1265 llvm::zip_equal(llvm::make_pointee_range(ImportingJobs),
1266 ModuleDepGraphsForScannedJobs)) {
1267 for (auto &MD : ModuleDepsGraph) {
1268 const auto Inserted = AlreadySeen.insert(MD.ID).second;
1269 if (!Inserted)
1270 continue;
1271
1272 auto ClangModuleJob = createClangModulePrecompileJob(C, ImportingJob, MD);
1273 Graph.createJobNode<ClangModuleJobNode>(std::move(ClangModuleJob),
1274 std::move(MD));
1275 }
1276 }
1277}
1278
1279/// Installs the command lines produced by the dependency scan into
1280/// \p ScannedJobs.
1281static void
1283 MutableArrayRef<std::unique_ptr<Command>> ScannedJobs,
1284 ArrayRef<InputDependencies> InputDepsForScannedJobs) {
1285 for (auto &&[Job, InputDeps] : llvm::zip_equal(
1286 llvm::make_pointee_range(ScannedJobs), InputDepsForScannedJobs)) {
1287 const auto &BuildArgs = InputDeps.BuildArgs;
1288 ArgStringList JobArgs;
1289 JobArgs.reserve(BuildArgs.size());
1290
1291 const auto &SourceAction = Job.getSource();
1292 const auto &TC = Job.getCreator().getToolChain();
1293 auto &TCArgs =
1294 C.getArgsForToolChain(&TC, SourceAction.getOffloadingArch(),
1295 SourceAction.getOffloadingDeviceKind());
1296
1297 for (const auto &Arg : BuildArgs)
1298 JobArgs.push_back(TCArgs.MakeArgString(Arg));
1299
1300 Job.replaceArguments(std::move(JobArgs));
1301 }
1302}
1303
1304/// Creates nodes for all jobs which were scanned for dependencies.
1305///
1306/// The updated command lines produced by the dependency scan are installed at a
1307/// later point.
1309 CompilationGraph &Graph,
1310 SmallVectorImpl<std::unique_ptr<Command>> &&ScannedJobs,
1311 SmallVectorImpl<InputDependencies> &&InputDepsForScannedJobs) {
1312 for (auto &&[Job, InputDeps] :
1313 llvm::zip_equal(ScannedJobs, InputDepsForScannedJobs)) {
1314 if (InputDeps.ModuleName.empty())
1315 Graph.createJobNode<NonModuleTUJobNode>(std::move(Job),
1316 std::move(InputDeps));
1317 else
1318 Graph.createJobNode<NamedModuleJobNode>(std::move(Job),
1319 std::move(InputDeps));
1320 }
1321}
1322
1323template <typename LookupT, typename KeyRangeT>
1324static void connectEdgesViaLookup(CompilationGraph &Graph, CGNode &TgtNode,
1325 const LookupT &SrcNodeLookup,
1326 const KeyRangeT &SrcNodeLookupKeys,
1327 CGEdge::EdgeKind Kind) {
1328 for (const auto &Key : SrcNodeLookupKeys) {
1329 const auto It = SrcNodeLookup.find(Key);
1330 if (It == SrcNodeLookup.end())
1331 continue;
1332
1333 auto &SrcNode = *It->second;
1334 Graph.createEdge(Kind, SrcNode, TgtNode);
1335 }
1336}
1337
1338/// Create edges for regular (non-module) dependencies in \p Graph.
1339static void createRegularEdges(CompilationGraph &Graph) {
1340 llvm::DenseMap<StringRef, CGNode *> NodeByOutputFiles;
1341 for (auto *Node : Graph) {
1342 for (const auto &Output : cast<JobNode>(Node)->Job->getOutputFilenames()) {
1343 [[maybe_unused]] const bool Inserted =
1344 NodeByOutputFiles.try_emplace(Output, Node).second;
1345 assert(Inserted &&
1346 "Driver should not produce multiple jobs with identical outputs!");
1347 }
1348 }
1349
1350 for (auto *Node : Graph) {
1351 const auto &InputInfos = cast<JobNode>(Node)->Job->getInputInfos();
1352 auto InputFilenames = llvm::map_range(
1353 InputInfos, [](const auto &II) { return II.getFilename(); });
1354
1355 connectEdgesViaLookup(Graph, *Node, NodeByOutputFiles, InputFilenames,
1356 CGEdge::EdgeKind::Regular);
1357 }
1358}
1359
1360/// Create edges for module dependencies in \p Graph.
1361///
1362/// \returns false if there are multiple definitions for a named module, with
1363/// diagnostics reported to \p Diags; otherwise returns true.
1364static bool createModuleDependencyEdges(CompilationGraph &Graph,
1365 DiagnosticsEngine &Diags) {
1366 llvm::DenseMap<deps::ModuleID, CGNode *> ClangModuleNodeByID;
1367 llvm::DenseMap<ModuleNameAndTriple, CGNode *> NamedModuleNodeByID;
1368
1369 // Map each module to the job that produces it.
1370 bool HasDuplicateModuleError = false;
1371 for (auto *Node : Graph) {
1372 llvm::TypeSwitch<CGNode *>(Node)
1373 .Case([&](ClangModuleJobNode *ClangModuleNode) {
1374 [[maybe_unused]] const bool Inserted =
1375 ClangModuleNodeByID.try_emplace(ClangModuleNode->MD.ID, Node)
1376 .second;
1377 assert(Inserted &&
1378 "Multiple Clang module nodes with the same module ID!");
1379 })
1380 .Case([&](NamedModuleJobNode *NamedModuleNode) {
1381 StringRef ModuleName = NamedModuleNode->InputDeps.ModuleName;
1382 ModuleNameAndTriple ID{ModuleName, getTriple(*NamedModuleNode->Job)};
1383 const auto [It, Inserted] = NamedModuleNodeByID.try_emplace(ID, Node);
1384 if (!Inserted) {
1385 // For scan input jobs, their first input is always a filename and
1386 // the scanned source.
1387 // We don't use InputDeps.FileDeps here because diagnostics should
1388 // refer to the filename as specified on the command line, not the
1389 // canonical absolute path.
1390 StringRef PrevFile =
1391 getFirstInputFilename(*cast<JobNode>(It->second)->Job);
1392 StringRef CurFile = getFirstInputFilename(*NamedModuleNode->Job);
1393 Diags.Report(diag::err_modules_driver_named_module_redefinition)
1394 << ModuleName << PrevFile << CurFile;
1395 HasDuplicateModuleError = true;
1396 }
1397 });
1398 }
1399 if (HasDuplicateModuleError)
1400 return false;
1401
1402 // Create edges from the module nodes to their importers.
1403 for (auto *Node : Graph) {
1404 llvm::TypeSwitch<CGNode *>(Node)
1405 .Case([&](ClangModuleJobNode *ClangModuleNode) {
1406 connectEdgesViaLookup(Graph, *ClangModuleNode, ClangModuleNodeByID,
1407 ClangModuleNode->MD.ClangModuleDeps,
1408 CGEdge::EdgeKind::ModuleDependency);
1409 })
1410 .Case([&](ScannedJobNode *NodeWithInputDeps) {
1411 connectEdgesViaLookup(Graph, *NodeWithInputDeps, ClangModuleNodeByID,
1412 NodeWithInputDeps->InputDeps.ClangModuleDeps,
1413 CGEdge::EdgeKind::ModuleDependency);
1414
1415 StringRef Triple = getTriple(*NodeWithInputDeps->Job);
1416 const auto NamedModuleDepIDs =
1417 llvm::map_range(NodeWithInputDeps->InputDeps.NamedModuleDeps,
1418 [&](StringRef ModuleName) {
1419 return ModuleNameAndTriple{ModuleName, Triple};
1420 });
1421 connectEdgesViaLookup(Graph, *NodeWithInputDeps, NamedModuleNodeByID,
1422 NamedModuleDepIDs,
1423 CGEdge::EdgeKind::ModuleDependency);
1424 });
1425 }
1426
1427 return true;
1428}
1429
1430/// Prunes the compilation graph of any jobs which build Standard library
1431/// modules not required in this compilation.
1432static void
1433pruneUnusedStdlibModuleJobs(CompilationGraph &Graph,
1434 ArrayRef<JobNode *> UnusedStdlibModuleJobNodes) {
1435 // Collect all reachable non-image job nodes.
1436 llvm::SmallPtrSet<JobNode *, 16> PrunableJobNodes;
1437 for (auto *PrunableJobNodeRoot : UnusedStdlibModuleJobNodes) {
1438 auto ReachableJobNodes =
1439 llvm::map_range(llvm::depth_first(cast<CGNode>(PrunableJobNodeRoot)),
1440 llvm::CastTo<JobNode>);
1441 auto ReachableNonImageNodes = llvm::make_filter_range(
1442 ReachableJobNodes, [](auto *N) { return !llvm::isa<ImageJobNode>(N); });
1443 PrunableJobNodes.insert_range(ReachableNonImageNodes);
1444 }
1445
1446 // Map image job nodes to the prunable job nodes that feed into them.
1447 llvm::DenseMap<ImageJobNode *, llvm::SmallPtrSet<JobNode *, 4>>
1448 PrunableJobNodesByImageNode;
1449 for (auto *PrunableJobNode : PrunableJobNodes) {
1450 auto ReachableJobNodes = llvm::depth_first(cast<CGNode>(PrunableJobNode));
1451 auto ReachableImageJobNodes = llvm::map_range(
1452 llvm::make_filter_range(ReachableJobNodes, llvm::IsaPred<ImageJobNode>),
1453 llvm::CastTo<ImageJobNode>);
1454
1455 for (auto *ImageNode : ReachableImageJobNodes)
1456 PrunableJobNodesByImageNode[ImageNode].insert(PrunableJobNode);
1457 }
1458
1459 // Remove from each affected image job node any arguments corresponding to
1460 // outputs of the connected prunable job nodes.
1461 for (auto &[ImageNode, PrunableJobNodeInputs] : PrunableJobNodesByImageNode) {
1462 SmallVector<StringRef, 4> OutputsToRemove;
1463 for (auto *JN : PrunableJobNodeInputs)
1464 llvm::append_range(OutputsToRemove, JN->Job->getOutputFilenames());
1465
1466 auto NewArgs = ImageNode->Job->getArguments();
1467 llvm::erase_if(NewArgs, [&](StringRef Arg) {
1468 return llvm::is_contained(OutputsToRemove, Arg);
1469 });
1470 ImageNode->Job->replaceArguments(NewArgs);
1471 }
1472
1473 // Erase all prunable job nodes from the graph.
1474 for (auto *JN : PrunableJobNodes) {
1475 // Nodes are owned by the graph, but we can release the associated job.
1476 JN->Job.reset();
1477 Graph.removeNode(*JN);
1478 }
1479}
1480
1481/// Creates the root node and connects it to all nodes with no incoming edges
1482/// ensuring that every node in the graph is reachable from the root.
1483static void createAndConnectRoot(CompilationGraph &Graph) {
1484 llvm::SmallPtrSet<CGNode *, 16> HasIncomingEdge;
1485 for (auto *Node : Graph)
1486 for (auto *Edge : Node->getEdges())
1487 HasIncomingEdge.insert(&Edge->getTargetNode());
1488
1489 auto AllNonRootNodes = llvm::iterator_range(Graph);
1490 auto &Root = Graph.createRoot();
1491
1492 for (auto *Node : AllNonRootNodes) {
1493 if (HasIncomingEdge.contains(Node))
1494 continue;
1495 Graph.createEdge(CGEdge::EdgeKind::Rooted, Root, *Node);
1496 }
1497}
1498
1501 llvm::PrettyStackTraceString CrashInfo("Running modules driver.");
1502
1503 auto Jobs = C.getJobs().takeJobs();
1504
1505 const auto ManifestEntryBySource = buildManifestLookupMap(ManifestEntries);
1506 // Apply manifest-entry specific command-line modifications before the scan as
1507 // they might affect it.
1508 applyArgsForStdModuleManifestInputs(C, ManifestEntryBySource, Jobs);
1509
1510 DiagnosticsEngine &Diags = C.getDriver().getDiags();
1511
1512 // Run the dependency scan.
1513 const auto MaybeModuleCachePath = getModuleCachePath(C.getArgs());
1514 if (!MaybeModuleCachePath) {
1515 Diags.Report(diag::err_default_modules_cache_not_available);
1516 return;
1517 }
1518
1519 auto MaybeCWD = C.getDriver().getVFS().getCurrentWorkingDirectory();
1520 const auto CWD = MaybeCWD ? std::move(*MaybeCWD) : ".";
1521
1522 auto MaybeScanResults = scanDependencies(Jobs, ManifestEntryBySource,
1523 *MaybeModuleCachePath, CWD, Diags);
1524 if (!MaybeScanResults) {
1525 Diags.Report(diag::err_dependency_scan_failed);
1526 return;
1527 }
1528 auto &ScanResult = *MaybeScanResults;
1529
1530 // Build the compilation graph.
1531 CompilationGraph Graph;
1533 Graph, takeJobsAtIndices(Jobs, ScanResult.NonScannableJobIndices));
1534 auto UnusedStdlibModuleJobNodes = createNodesForUnusedStdlibModuleJobs(
1535 Graph, takeJobsAtIndices(Jobs, ScanResult.UnusedStdlibModuleJobIndices));
1536
1537 auto ScannedJobs = takeJobsAtIndices(Jobs, ScanResult.ScannedJobIndices);
1539 Graph, C, /*ImportingJobs*/ ScannedJobs,
1540 std::move(ScanResult.ModuleDepGraphsForScannedJobs));
1541 installScanCommandLines(C, ScannedJobs, ScanResult.InputDepsForScannedJobs);
1542 createNodesForScannedJobs(Graph, std::move(ScannedJobs),
1543 std::move(ScanResult.InputDepsForScannedJobs));
1544
1545 createRegularEdges(Graph);
1546 pruneUnusedStdlibModuleJobs(Graph, UnusedStdlibModuleJobNodes);
1547 if (!createModuleDependencyEdges(Graph, Diags))
1548 return;
1549 createAndConnectRoot(Graph);
1550
1551 Diags.Report(diag::remark_printing_module_graph);
1552 if (!Diags.isLastDiagnosticIgnored())
1553 llvm::WriteGraph<const CompilationGraph *>(llvm::errs(), &Graph);
1554
1555 // TODO: Fix-up command-lines for named module imports.
1556
1557 llvm::ReversePostOrderTraversal<CompilationGraph *> TopologicallySortedNodes(
1558 &Graph);
1559 assert(isa<RootNode>(*TopologicallySortedNodes.begin()) &&
1560 "First node in topological order must be the root!");
1561 auto TopologicallySortedJobNodes = llvm::map_range(
1562 llvm::drop_begin(TopologicallySortedNodes), llvm::CastTo<JobNode>);
1563 for (auto *JN : TopologicallySortedJobNodes)
1564 C.addCommand(std::move(JN->Job));
1565}
Defines the Diagnostic-related interfaces.
static Decl::Kind getKind(const Decl *D)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static std::optional< DependencyScanResult > scanDependencies(ArrayRef< std::unique_ptr< Command > > Jobs, llvm::DenseMap< StringRef, const StdModuleManifest::Module * > ManifestLookup, StringRef ModuleCachePath, StringRef WorkingDirectory, DiagnosticsEngine &Diags)
Scans the compilations job list Jobs for module dependencies.
static std::string constructPCMPath(const deps::ModuleID &ID, StringRef OutputDir)
Construct a path for the explicitly built PCM.
static StringRef getTriple(const Command &Job)
static void reportAllScanDiagnostics(SmallVectorImpl< SmallVector< StandaloneDiagnostic, 0 > > &&AllScanDiags, DiagnosticsEngine &Diags)
Report the diagnostics collected during each dependency scan.
static const StdModuleManifest::Module * getManifestEntryForCommand(const Command &Job, const ManifestEntryLookup &ManifestEntryBySource)
Returns the manifest entry corresponding to Job, or nullptr if none exists.
static bool isDependencyScannableJob(const Command &Job)
Returns true if a dependency scan can be performed using Job.
static std::pair< std::unique_ptr< llvm::ThreadPoolInterface >, std::unique_ptr< ScanningWorkerPool > > createOptimalThreadAndWorkerPool(size_t NumScanInputs, bool HasStdlibModuleInputs, deps::DependencyScanningService &ScanningService)
static StringRef getFirstInputFilename(const Command &Job)
static SmallVector< std::unique_ptr< Command > > takeJobsAtIndices(SmallVectorImpl< std::unique_ptr< Command > > &Jobs, ArrayRef< size_t > Indices)
static void pruneUnusedStdlibModuleJobs(CompilationGraph &Graph, ArrayRef< JobNode * > UnusedStdlibModuleJobNodes)
Prunes the compilation graph of any jobs which build Standard library modules not required in this co...
static Expected< StdModuleManifest > parseManifest(StringRef Buffer)
Parses the Standard library module manifest from Buffer.
static void createNodesForScannedJobs(CompilationGraph &Graph, SmallVectorImpl< std::unique_ptr< Command > > &&ScannedJobs, SmallVectorImpl< InputDependencies > &&InputDepsForScannedJobs)
Creates nodes for all jobs which were scanned for dependencies.
std::pair< StringRef, StringRef > ModuleNameAndTriple
static void createAndConnectRoot(CompilationGraph &Graph)
Creates the root node and connects it to all nodes with no incoming edges ensuring that every node in...
static void makeManifestPathsAbsolute(MutableArrayRef< StdModuleManifest::Module > ManifestEntries, StringRef ManifestPath)
Converts each file path in manifest from relative to absolute.
static SmallVector< std::string, 0 > buildCommandLine(const Command &Job)
Constructs the full command line, including the executable, for Job.
static void applyArgsForStdModuleManifestInputs(Compilation &C, const ManifestEntryLookup &ManifestEntryBySource, MutableArrayRef< std::unique_ptr< Command > > Jobs)
Apply command-line modifications specific for inputs originating from the Standard library module man...
static bool createModuleDependencyEdges(CompilationGraph &Graph, DiagnosticsEngine &Diags)
Create edges for module dependencies in Graph.
static std::pair< std::optional< deps::TranslationUnitDeps >, SmallVector< StandaloneDiagnostic, 0 > > scanDependenciesForJob(const Command &Job, ScanningWorkerPool &WorkerPool, StringRef WorkingDirectory, ModuleLookupController &LookupController)
Performs a dependency scan for a single job.
static std::unique_ptr< CC1Command > createClangModulePrecompileJob(Compilation &C, const Command &ImportingJob, const deps::ModuleDeps &MD)
Creates a job for the Clang module described by MD.
static void addSystemIncludeDirsFromManifest(Compilation &C, Command &Job, ArgStringList &CC1Args, ArrayRef< std::string > SystemIncludeDirs)
Adds all SystemIncludeDirs to the CC1Args of Job.
static InputDependencies makeInputDeps(deps::TranslationUnitDeps &&TUDeps)
static void createNodesForNonScannableJobs(CompilationGraph &Graph, SmallVectorImpl< std::unique_ptr< Command > > &&NonScannableJobs)
Creates nodes for all jobs that could not be scanned (e.g. image jobs, ...).
static SmallVector< JobNode * > createNodesForUnusedStdlibModuleJobs(CompilationGraph &Graph, SmallVectorImpl< std::unique_ptr< Command > > &&UnusedStdlibModuleJobs)
Creates nodes for the Standard library module jobs not discovered as dependencies.
static ManifestEntryLookup buildManifestLookupMap(ArrayRef< StdModuleManifest::Module > ManifestEntries)
Builds a mapping from a module's source path to its entry in the manifest.
static void createRegularEdges(CompilationGraph &Graph)
Create edges for regular (non-module) dependencies in Graph.
static void createClangModuleJobsAndNodes(CompilationGraph &Graph, Compilation &C, ArrayRef< std::unique_ptr< Command > > ImportingJobs, SmallVectorImpl< deps::ModuleDepsGraph > &&ModuleDepGraphsForScannedJobs)
Creates a ClangModuleJobNode with associated job for each unique Clang module in ModuleDepGraphsForSc...
static void installScanCommandLines(Compilation &C, MutableArrayRef< std::unique_ptr< Command > > ScannedJobs, ArrayRef< InputDependencies > InputDepsForScannedJobs)
Installs the command lines produced by the dependency scan into ScannedJobs.
static void connectEdgesViaLookup(CompilationGraph &Graph, CGNode &TgtNode, const LookupT &SrcNodeLookup, const KeyRangeT &SrcNodeLookupKeys, CGEdge::EdgeKind Kind)
static bool isCC1Job(const Command &Job)
llvm::DenseMap< StringRef, const StdModuleManifest::Module * > ManifestEntryLookup
static std::optional< std::string > getModuleCachePath(llvm::opt::DerivedArgList &Args)
Computes the -fmodule-cache-path for this compilation.
This file defines functionality to support driver managed builds for compilations which use Clang mod...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
virtual void EndSourceFile()
Callback to inform the diagnostic client that processing of a source file has ended.
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)
Callback to inform the diagnostic client that processing of a source file is beginning.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:233
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasSourceManager() const
Definition Diagnostic.h:623
bool isLastDiagnosticIgnored() const
Determine whether the previous diagnostic was ignored.
Definition Diagnostic.h:810
SourceManager & getSourceManager() const
Definition Diagnostic.h:625
Level
The level of the diagnostic, after it has been through mapping.
Definition Diagnostic.h:238
DiagnosticConsumer * getClient()
Definition Diagnostic.h:613
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:53
Keeps track of options that affect how file operations are performed.
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
This class handles loading and caching of source files into memory.
FileManager & getFileManager() const
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
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...
Action - Represent an abstract compilation step to perform.
Definition Action.h:47
const char * getOffloadingArch() const
Definition Action.h:213
void propagateOffloadInfo(const Action *A)
Set the offload info of this action to be the same as the provided action, and propagate it to its de...
Definition Action.cpp:96
OffloadKind getOffloadingDeviceKind() const
Definition Action.h:212
Command - An executable path/name and argument vector to execute.
Definition Job.h:106
const Action & getSource() const
getSource - Return the Action which caused the creation of this job.
Definition Job.h:188
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
Definition Job.h:191
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:224
const char * getExecutable() const
Definition Job.h:222
const std::vector< InputInfo > & getInputInfos() const
Definition Job.h:226
Compilation - A set of tasks to perform for a single driver invocation.
Definition Compilation.h:45
static bool getDefaultModuleCachePath(SmallVectorImpl< char > &Result)
Compute the default -fmodule-cache-path.
Definition Clang.cpp:3834
ToolChain - Access to tools for a single platform.
Definition ToolChain.h:92
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path)
Utility function to add a system include directory to CC1 arguments.
const llvm::Triple & getTriple() const
Definition ToolChain.h:263
const ToolChain & getToolChain() const
Definition Tool.h:52
const char * getName() const
Definition Tool.h:48
GraphWriterBase< GraphType, GraphWriter< GraphType > > Base
GraphWriter(llvm::raw_ostream &O, const GraphType &G, bool IsSimple)
@ VFS
Remove unused -ivfsoverlay arguments.
ModuleOutputKind
An output from a module compilation, such as the path of the module file.
@ ModuleFile
The module file (.pcm). Required.
void buildStdModuleManifestInputs(ArrayRef< StdModuleManifest::Module > ManifestEntries, Compilation &C, InputList &Inputs)
Constructs compilation inputs for each module listed in the provided Standard library module manifest...
void runModulesDriver(Compilation &C, ArrayRef< StdModuleManifest::Module > ManifestEntries)
Scans the compilation inputs for module dependencies and adjusts the compilation to build and supply ...
llvm::Expected< StdModuleManifest > readStdModuleManifest(llvm::StringRef ManifestPath, llvm::vfs::FileSystem &VFS)
Reads the Standard library module manifest at ManifestPath.
static bool fromJSON(const llvm::json::Value &Params, StdModuleManifest::Module::LocalArguments &LocalArgs, llvm::json::Path P)
bool isSrcFile(ID Id)
isSrcFile - Is this a source file, i.e.
Definition Types.cpp:305
llvm::opt::Arg * makeInputArg(llvm::opt::DerivedArgList &Args, const llvm::opt::OptTable &Opts, StringRef Value, bool Claim=true)
Creates and adds a synthesized input argument.
llvm::SmallVector< InputTy, 16 > InputList
A list of inputs and their types for the given arguments.
Definition Types.h:136
NodeKind
A kind of a syntax node, used for implementing casts.
Definition Nodes.h:32
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
static bool classof(const OMPClause *T)
@ NumWorkers
'num_workers' clause, allowed on 'parallel', 'kernels', parallel loop', and 'kernels loop' constructs...
U cast(CodeGen::Address addr)
Definition Address.h:327
StoredDiagnostic translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, const StandaloneDiagnostic &StandaloneDiag, llvm::StringMap< SourceLocation > &SrcLocCache)
Translates StandaloneDiag into a StoredDiagnostic, associating it with the provided FileManager and S...
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
int const char * function
Definition c++config.h:31
The configuration knobs for the dependency scanning service.
ModuleID ID
The identifier of the module.
std::vector< ModuleID > ClangModuleDeps
A list of module identifiers this module directly depends on, not including transitive dependencies.
const std::vector< std::string > & getBuildArguments() const
Get (or compute) the compiler invocation that can be used to build this module.
This is used to identify a specific module.
The full dependencies and module graph for a specific input.
static constexpr ResponseFileSupport AtFileUTF8()
Definition Job.h:85
std::optional< LocalArguments > LocalArgs
The parsed Standard library module manifest.
static std::string getNodeIdentifier(NodeRef N, GraphRef)
static std::string getNodeLabel(NodeRef N, GraphRef)
static std::string getNodeAttributes(NodeRef N, GraphRef)
static bool isNodeHidden(NodeRef N, GraphRef)
static ChildEdgeIteratorType child_edge_end(NodeRef N)
mapped_iterator< CGNode::iterator, decltype(&CGGetTargetNode)> ChildIteratorType
static ChildEdgeIteratorType child_edge_begin(NodeRef N)
CGNode::iterator ChildEdgeIteratorType
static ChildIteratorType child_end(NodeRef N)
static NodeRef CGGetTargetNode(CGEdge *E)
static NodeRef getEntryNode(NodeRef N)
static ChildIteratorType child_begin(NodeRef N)
static NodeRef getEntryNode(GraphRef G)
static nodes_iterator nodes_begin(GraphRef G)
CompilationGraph::iterator nodes_iterator
static nodes_iterator nodes_end(GraphRef G)
static ChildIteratorType child_begin(NodeRef N)
mapped_iterator< CGNode::const_iterator, decltype(&CGGetTargetNode)> ChildIteratorType
static ChildEdgeIteratorType child_edge_end(NodeRef N)
static ChildEdgeIteratorType child_edge_begin(NodeRef N)
CGNode::const_iterator ChildEdgeIteratorType
static ChildIteratorType child_end(NodeRef N)
static NodeRef getEntryNode(NodeRef N)
static NodeRef CGGetTargetNode(const CGEdge *E)
static nodes_iterator nodes_begin(GraphRef G)
CompilationGraph::const_iterator nodes_iterator
static nodes_iterator nodes_end(GraphRef G)