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