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_CXXStdModule, 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 MainInput.getType() != types::TY_CXXStdModule) {
1218 Diags.Report(diag::err_module_defined_outside_of_module_source)
1219 << InputDeps.ModuleName << MainInput.getFilename();
1220 return false;
1221 }
1222 }
1223 return true;
1224}
1225
1227takeJobsAtIndices(SmallVectorImpl<std::unique_ptr<Command>> &Jobs,
1228 ArrayRef<size_t> Indices) {
1230 for (const auto JobIndex : Indices) {
1231 assert(Jobs[JobIndex] && "Expected valid job!");
1232 Out.push_back(std::move(Jobs[JobIndex]));
1233 }
1234 return Out;
1235}
1236
1237/// Creates nodes for all jobs that could not be scanned (e.g. image jobs, ...).
1239 CompilationGraph &Graph,
1240 SmallVectorImpl<std::unique_ptr<Command>> &&NonScannableJobs) {
1241 for (auto &Job : NonScannableJobs) {
1242 if (Job->getCreator().isLinkJob())
1243 Graph.createJobNode<ImageJobNode>(std::move(Job));
1244 else
1245 Graph.createJobNode<MiscJobNode>(std::move(Job));
1246 }
1247}
1248
1249/// Creates nodes for the Standard library module jobs not discovered as
1250/// dependencies.
1251///
1252/// These and any dependent (non-image) job nodes should be pruned from the
1253/// graph later.
1255 CompilationGraph &Graph,
1256 SmallVectorImpl<std::unique_ptr<Command>> &&UnusedStdlibModuleJobs) {
1257 SmallVector<JobNode *> StdlibModuleNodesToPrune;
1258 for (auto &Job : UnusedStdlibModuleJobs) {
1259 auto &NewNode = Graph.createJobNode<MiscJobNode>(std::move(Job));
1260 StdlibModuleNodesToPrune.push_back(&NewNode);
1261 }
1262 return StdlibModuleNodesToPrune;
1263}
1264
1265// Returns the derived argument list for the tool chain responsible
1266// for creating \p Job.
1267static const DerivedArgList &getToolChainArgs(Compilation &C,
1268 const Command &Job) {
1269 const auto &TC = Job.getCreator().getToolChain();
1270 const auto &SourceAction = Job.getSource();
1271 return C.getArgsForToolChain(&TC, SourceAction.getOffloadingArch(),
1272 SourceAction.getOffloadingDeviceKind());
1273}
1274
1275/// Creates a job for the Clang module described by \p MD.
1276static std::unique_ptr<Command>
1278 const deps::ModuleDeps &MD) {
1279 DerivedArgList &Args = C.getArgs();
1280 const OptTable &Opts = C.getDriver().getOpts();
1281 Arg *InputArg = makeInputArg(Args, Opts, "<discovered clang module>");
1282 Action *IA = C.MakeAction<InputAction>(*InputArg, types::ID::TY_ModuleFile);
1283 Action *PA = C.MakeAction<PrecompileJobAction>(IA, types::ID::TY_ModuleFile);
1284 PA->propagateOffloadInfo(&ImportingJob.getSource());
1285
1286 const auto &TCArgs = getToolChainArgs(C, ImportingJob);
1287
1288 const auto &BuildArgs = MD.getBuildArguments();
1289 ArgStringList JobArgs;
1290 JobArgs.reserve(BuildArgs.size());
1291 for (const auto &Arg : BuildArgs)
1292 JobArgs.push_back(TCArgs.MakeArgString(Arg));
1293
1294 const auto &D = C.getDriver();
1295 return std::make_unique<Command>(
1296 *PA, ImportingJob.getCreator(), ResponseFileSupport::AtFileUTF8(),
1297 D.getDriverProgramPath(), JobArgs,
1298 /*Inputs=*/ArrayRef<InputInfo>{},
1299 /*Outputs=*/ArrayRef<InputInfo>{}, D.getPrependArg());
1300}
1301
1302/// Creates a \c ClangModuleJobNode with associated job for each unique Clang
1303/// module in \p ModuleDepGraphsForScannedJobs.
1304///
1305/// \param ImportingJobs Jobs whose module dependencies were scanned.
1306/// \param ModuleDepGraphsForScannedJobs Full Clang module dependency graphs
1307/// corresponding to \p ImportingJobs, in order.
1309 CompilationGraph &Graph, Compilation &C,
1310 ArrayRef<std::unique_ptr<Command>> ImportingJobs,
1311 SmallVectorImpl<deps::ModuleDepsGraph> &&ModuleDepGraphsForScannedJobs) {
1312 llvm::DenseSet<deps::ModuleID> AlreadySeen;
1313 for (auto &&[ImportingJob, ModuleDepsGraph] :
1314 llvm::zip_equal(llvm::make_pointee_range(ImportingJobs),
1315 ModuleDepGraphsForScannedJobs)) {
1316 for (auto &MD : ModuleDepsGraph) {
1317 const auto Inserted = AlreadySeen.insert(MD.ID).second;
1318 if (!Inserted)
1319 continue;
1320
1321 auto ClangModuleJob = createClangModulePrecompileJob(C, ImportingJob, MD);
1322 Graph.createJobNode<ClangModuleJobNode>(std::move(ClangModuleJob),
1323 std::move(MD));
1324 }
1325 }
1326}
1327
1328/// Installs the command lines produced by the dependency scan into
1329/// \p ScannedJobs.
1330static void
1332 MutableArrayRef<std::unique_ptr<Command>> ScannedJobs,
1333 ArrayRef<InputDependencies> InputDepsForScannedJobs) {
1334 for (auto &&[Job, InputDeps] : llvm::zip_equal(
1335 llvm::make_pointee_range(ScannedJobs), InputDepsForScannedJobs)) {
1336 const auto &BuildArgs = InputDeps.BuildArgs;
1337 ArgStringList JobArgs;
1338 JobArgs.reserve(BuildArgs.size());
1339
1340 auto &TCArgs = getToolChainArgs(C, Job);
1341 for (const auto &Arg : BuildArgs)
1342 JobArgs.push_back(TCArgs.MakeArgString(Arg));
1343
1344 Job.replaceArguments(std::move(JobArgs));
1345 }
1346}
1347
1348/// Creates nodes for all jobs which were scanned for dependencies.
1349///
1350/// The updated command lines produced by the dependency scan are installed at a
1351/// later point.
1353 CompilationGraph &Graph,
1354 SmallVectorImpl<std::unique_ptr<Command>> &&ScannedJobs,
1355 SmallVectorImpl<InputDependencies> &&InputDepsForScannedJobs) {
1356 for (auto &&[Job, InputDeps] :
1357 llvm::zip_equal(ScannedJobs, InputDepsForScannedJobs)) {
1358 if (InputDeps.ModuleName.empty())
1359 Graph.createJobNode<NonModuleTUJobNode>(std::move(Job),
1360 std::move(InputDeps));
1361 else
1362 Graph.createJobNode<NamedModuleJobNode>(std::move(Job),
1363 std::move(InputDeps));
1364 }
1365}
1366
1367template <typename LookupT, typename KeyRangeT>
1368static void connectEdgesViaLookup(CompilationGraph &Graph, CGNode &TgtNode,
1369 const LookupT &SrcNodeLookup,
1370 const KeyRangeT &SrcNodeLookupKeys,
1371 CGEdge::EdgeKind Kind) {
1372 for (const auto &Key : SrcNodeLookupKeys) {
1373 const auto It = SrcNodeLookup.find(Key);
1374 if (It == SrcNodeLookup.end())
1375 continue;
1376
1377 auto &SrcNode = *It->second;
1378 Graph.createEdge(Kind, SrcNode, TgtNode);
1379 }
1380}
1381
1382/// Create edges for regular (non-module) dependencies in \p Graph.
1383static void createRegularEdges(CompilationGraph &Graph) {
1384 llvm::DenseMap<StringRef, CGNode *> NodeByOutputFiles;
1385 for (auto *Node : Graph) {
1386 for (const auto &Output : cast<JobNode>(Node)->Job->getOutputFilenames()) {
1387 [[maybe_unused]] const bool Inserted =
1388 NodeByOutputFiles.try_emplace(Output, Node).second;
1389 assert(Inserted &&
1390 "Driver should not produce multiple jobs with identical outputs!");
1391 }
1392 }
1393
1394 for (auto *Node : Graph) {
1395 const auto &InputInfos = cast<JobNode>(Node)->Job->getInputInfos();
1396 auto InputFilenames = llvm::map_range(
1397 InputInfos, [](const auto &II) { return II.getFilename(); });
1398
1399 connectEdgesViaLookup(Graph, *Node, NodeByOutputFiles, InputFilenames,
1400 CGEdge::EdgeKind::Regular);
1401 }
1402}
1403
1404/// Create edges for module dependencies in \p Graph.
1405///
1406/// \returns false if there are multiple definitions for a named module, with
1407/// diagnostics reported to \p Diags; otherwise returns true.
1408static bool createModuleDependencyEdges(CompilationGraph &Graph,
1409 DiagnosticsEngine &Diags) {
1410 llvm::DenseMap<deps::ModuleID, CGNode *> ClangModuleNodeByID;
1411 llvm::DenseMap<ModuleNameAndTriple, CGNode *> NamedModuleNodeByID;
1412
1413 // Map each module to the job that produces it.
1414 bool HasDuplicateModuleError = false;
1415 for (auto *Node : Graph) {
1416 llvm::TypeSwitch<CGNode *>(Node)
1417 .Case([&](ClangModuleJobNode *ClangModuleNode) {
1418 [[maybe_unused]] const bool Inserted =
1419 ClangModuleNodeByID.try_emplace(ClangModuleNode->MD.ID, Node)
1420 .second;
1421 assert(Inserted &&
1422 "Multiple Clang module nodes with the same module ID!");
1423 })
1424 .Case([&](NamedModuleJobNode *NamedModuleNode) {
1425 StringRef ModuleName = NamedModuleNode->InputDeps.ModuleName;
1426 ModuleNameAndTriple ID{ModuleName, getTriple(*NamedModuleNode->Job)};
1427 const auto [It, Inserted] = NamedModuleNodeByID.try_emplace(ID, Node);
1428 if (!Inserted) {
1429 // For scan input jobs, their first input is always a filename and
1430 // the scanned source.
1431 // We don't use InputDeps.FileDeps here because diagnostics should
1432 // refer to the filename as specified on the command line, not the
1433 // canonical absolute path.
1434 StringRef PrevFile =
1435 getFirstInputFilename(*cast<JobNode>(It->second)->Job);
1436 StringRef CurFile = getFirstInputFilename(*NamedModuleNode->Job);
1437 Diags.Report(diag::err_modules_driver_named_module_redefinition)
1438 << ModuleName << PrevFile << CurFile;
1439 HasDuplicateModuleError = true;
1440 }
1441 });
1442 }
1443 if (HasDuplicateModuleError)
1444 return false;
1445
1446 // Create edges from the module nodes to their importers.
1447 for (auto *Node : Graph) {
1448 llvm::TypeSwitch<CGNode *>(Node)
1449 .Case([&](ClangModuleJobNode *ClangModuleNode) {
1450 connectEdgesViaLookup(Graph, *ClangModuleNode, ClangModuleNodeByID,
1451 ClangModuleNode->MD.ClangModuleDeps,
1452 CGEdge::EdgeKind::ModuleDependency);
1453 })
1454 .Case([&](ScannedJobNode *NodeWithInputDeps) {
1455 connectEdgesViaLookup(Graph, *NodeWithInputDeps, ClangModuleNodeByID,
1456 NodeWithInputDeps->InputDeps.ClangModuleDeps,
1457 CGEdge::EdgeKind::ModuleDependency);
1458
1459 StringRef Triple = getTriple(*NodeWithInputDeps->Job);
1460 const auto NamedModuleDepIDs =
1461 llvm::map_range(NodeWithInputDeps->InputDeps.NamedModuleDeps,
1462 [&](StringRef ModuleName) {
1463 return ModuleNameAndTriple{ModuleName, Triple};
1464 });
1465 connectEdgesViaLookup(Graph, *NodeWithInputDeps, NamedModuleNodeByID,
1466 NamedModuleDepIDs,
1467 CGEdge::EdgeKind::ModuleDependency);
1468 });
1469 }
1470
1471 return true;
1472}
1473
1474/// Prunes the compilation graph of any jobs which build Standard library
1475/// modules not required in this compilation.
1476static void
1477pruneUnusedStdlibModuleJobs(CompilationGraph &Graph,
1478 ArrayRef<JobNode *> UnusedStdlibModuleJobNodes) {
1479 // Collect all reachable non-image job nodes.
1480 llvm::SmallPtrSet<JobNode *, 16> PrunableJobNodes;
1481 for (auto *PrunableJobNodeRoot : UnusedStdlibModuleJobNodes) {
1482 auto ReachableJobNodes =
1483 llvm::map_range(llvm::depth_first(cast<CGNode>(PrunableJobNodeRoot)),
1484 llvm::CastTo<JobNode>);
1485 auto ReachableNonImageNodes = llvm::make_filter_range(
1486 ReachableJobNodes, [](auto *N) { return !llvm::isa<ImageJobNode>(N); });
1487 PrunableJobNodes.insert_range(ReachableNonImageNodes);
1488 }
1489
1490 // Map image job nodes to the prunable job nodes that feed into them.
1491 llvm::DenseMap<ImageJobNode *, llvm::SmallPtrSet<JobNode *, 4>>
1492 PrunableJobNodesByImageNode;
1493 for (auto *PrunableJobNode : PrunableJobNodes) {
1494 auto ReachableJobNodes = llvm::depth_first(cast<CGNode>(PrunableJobNode));
1495 auto ReachableImageJobNodes = llvm::map_range(
1496 llvm::make_filter_range(ReachableJobNodes, llvm::IsaPred<ImageJobNode>),
1497 llvm::CastTo<ImageJobNode>);
1498
1499 for (auto *ImageNode : ReachableImageJobNodes)
1500 PrunableJobNodesByImageNode[ImageNode].insert(PrunableJobNode);
1501 }
1502
1503 // Remove from each affected image job node any arguments corresponding to
1504 // outputs of the connected prunable job nodes.
1505 for (auto &[ImageNode, PrunableJobNodeInputs] : PrunableJobNodesByImageNode) {
1506 SmallVector<StringRef, 4> OutputsToRemove;
1507 for (auto *JN : PrunableJobNodeInputs)
1508 llvm::append_range(OutputsToRemove, JN->Job->getOutputFilenames());
1509
1510 auto NewArgs = ImageNode->Job->getArguments();
1511 llvm::erase_if(NewArgs, [&](StringRef Arg) {
1512 return llvm::is_contained(OutputsToRemove, Arg);
1513 });
1514 ImageNode->Job->replaceArguments(NewArgs);
1515 }
1516
1517 // Erase all prunable job nodes from the graph.
1518 for (auto *JN : PrunableJobNodes) {
1519 // Nodes are owned by the graph, but we can release the associated job.
1520 JN->Job.reset();
1521 Graph.removeNode(*JN);
1522 }
1523}
1524
1525/// Creates the root node and connects it to all nodes with no incoming edges
1526/// ensuring that every node in the graph is reachable from the root.
1527static void createAndConnectRoot(CompilationGraph &Graph) {
1528 llvm::SmallPtrSet<CGNode *, 16> HasIncomingEdge;
1529 for (auto *Node : Graph)
1530 for (auto *Edge : Node->getEdges())
1531 HasIncomingEdge.insert(&Edge->getTargetNode());
1532
1533 auto AllNonRootNodes = llvm::iterator_range(Graph);
1534 auto &Root = Graph.createRoot();
1535
1536 for (auto *Node : AllNonRootNodes) {
1537 if (HasIncomingEdge.contains(Node))
1538 continue;
1539 Graph.createEdge(CGEdge::EdgeKind::Rooted, Root, *Node);
1540 }
1541}
1542
1543/// Creates a temporary output path for \p ModuleName.
1544static std::string createModuleOutputPath(const Compilation &C,
1545 StringRef ModuleName) {
1546 // Sanitize the ':' included in parition names. It is illegal for filenames on
1547 // Windows.
1548 SmallString<32> SanitizedModuleName(ModuleName);
1549 llvm::replace(SanitizedModuleName, ':', '-');
1550 auto ModuleOutputPath = C.getDriver().GetTemporaryPath(
1551 SanitizedModuleName, types::getTypeTempSuffix(types::TY_ModuleFile));
1552 return ModuleOutputPath;
1553}
1554
1555/// Adds the '-fmodule-output=' argument for the module produced by \p Node.
1557 NamedModuleJobNode &Node,
1558 StringRef ModuleOutputPath) {
1559 auto &Job = *Node.Job;
1560 const auto &TCArgs = getToolChainArgs(C, Job);
1561 auto JobArgs = Job.getArguments();
1562 JobArgs.push_back(
1563 TCArgs.MakeArgString("-fmodule-output=" + ModuleOutputPath));
1564 Job.replaceArguments(std::move(JobArgs));
1565}
1566
1567/// Propagates the '-fmodule-file=' mapping for the named module described by
1568/// \p Node to each dependent job.
1570 NamedModuleJobNode &Node,
1571 StringRef ModuleOutputPath) {
1572 const StringRef ModuleName = Node.InputDeps.ModuleName;
1573
1574 auto DependentNodes = llvm::drop_begin(llvm::depth_first<CGNode *>(&Node));
1575 auto DependentScannedNodes = llvm::map_range(
1576 llvm::make_filter_range(DependentNodes, llvm::IsaPred<ScannedJobNode>),
1577 llvm::CastTo<ScannedJobNode>);
1578
1579 for (ScannedJobNode *DependentNode : DependentScannedNodes) {
1580 auto &DependentJob = *DependentNode->Job;
1581 const auto &TCArgs = getToolChainArgs(C, DependentJob);
1582 auto JobArgs = DependentJob.getArguments();
1583 JobArgs.push_back(TCArgs.MakeArgString("-fmodule-file=" + ModuleName + "=" +
1584 ModuleOutputPath));
1585 DependentJob.replaceArguments(std::move(JobArgs));
1586 }
1587}
1588
1589/// Finalizes command lines for C++20 named module dependencies.
1590///
1591/// The command lines produced by dependency scanning are only adjusted to
1592/// handle discovered Clang modules. For C++20 named modules, we update the
1593/// command-lines here.
1595 CompilationGraph &Graph) {
1596 const auto NamedModuleNodes = llvm::map_range(
1597 llvm::make_filter_range(Graph, llvm::IsaPred<NamedModuleJobNode>),
1598 llvm::CastTo<NamedModuleJobNode>);
1599
1600 for (NamedModuleJobNode *Node : NamedModuleNodes) {
1601 const auto &Job = *Node->Job;
1602
1603 // For Standard library modules, the driver already creates the module
1604 // output as a temp file, so we can use that path directly.
1605 const bool IsStdModule =
1606 Job.getInputInfos().front().getType() == types::TY_CXXStdModule;
1607 if (IsStdModule) {
1608 StringRef ModuleOutputPath = Job.getOutputFilenames().front();
1609 propagateModuleFileMappingArg(C, *Node, ModuleOutputPath);
1610 continue;
1611 }
1612
1613 const StringRef ModuleName = Node->InputDeps.ModuleName;
1614 const auto ModuleOutputPath = createModuleOutputPath(C, ModuleName);
1615 C.addTempFile(C.getArgs().MakeArgString(ModuleOutputPath));
1616
1617 configureNamedModuleOutputArg(C, *Node, ModuleOutputPath);
1618 propagateModuleFileMappingArg(C, *Node, ModuleOutputPath);
1619 }
1620}
1621
1622/// Moves jobs from \p Graph into \p C in the graph's topological order.
1624 CompilationGraph &&Graph) {
1625 llvm::ReversePostOrderTraversal<CompilationGraph *> TopologicallySortedNodes(
1626 &Graph);
1627 assert(isa<RootNode>(*TopologicallySortedNodes.begin()) &&
1628 "First node in topological order must be the root!");
1629 auto TopologicallySortedJobNodes = llvm::map_range(
1630 llvm::drop_begin(TopologicallySortedNodes), llvm::CastTo<JobNode>);
1631 for (auto *JN : TopologicallySortedJobNodes)
1632 C.addCommand(std::move(JN->Job));
1633}
1634
1637 llvm::PrettyStackTraceString CrashInfo("Running modules driver.");
1638
1639 auto Jobs = C.getJobs().takeJobs();
1640
1641 const auto ManifestEntryBySource = buildManifestLookupMap(ManifestEntries);
1642 // Apply manifest-entry specific command-line modifications before the scan as
1643 // they might affect it.
1644 applyArgsForStdModuleManifestInputs(C, ManifestEntryBySource, Jobs);
1645
1646 DiagnosticsEngine &Diags = C.getDriver().getDiags();
1647
1648 // Run the dependency scan.
1649 const auto MaybeModuleCachePath = getModuleCachePath(C.getArgs());
1650 if (!MaybeModuleCachePath) {
1651 Diags.Report(diag::err_default_modules_cache_not_available);
1652 return;
1653 }
1654
1655 auto MaybeCWD = C.getDriver().getVFS().getCurrentWorkingDirectory();
1656 const auto CWD = MaybeCWD ? std::move(*MaybeCWD) : ".";
1657
1658 auto MaybeScanResults = scanDependencies(Jobs, ManifestEntryBySource,
1659 *MaybeModuleCachePath, CWD, Diags);
1660 if (!MaybeScanResults) {
1661 Diags.Report(diag::err_dependency_scan_failed);
1662 return;
1663 }
1664 auto &ScanResult = *MaybeScanResults;
1665
1666 // Build the compilation graph.
1667 CompilationGraph Graph;
1669 Graph, takeJobsAtIndices(Jobs, ScanResult.NonScannableJobIndices));
1670 auto UnusedStdlibModuleJobNodes = createNodesForUnusedStdlibModuleJobs(
1671 Graph, takeJobsAtIndices(Jobs, ScanResult.UnusedStdlibModuleJobIndices));
1672
1673 auto ScannedJobs = takeJobsAtIndices(Jobs, ScanResult.ScannedJobIndices);
1674 if (!validateScannedJobInputKinds(ScannedJobs,
1675 ScanResult.InputDepsForScannedJobs, Diags))
1676 return;
1677 installScanCommandLines(C, ScannedJobs, ScanResult.InputDepsForScannedJobs);
1678
1680 Graph, C, /*ImportingJobs*/ ScannedJobs,
1681 std::move(ScanResult.ModuleDepGraphsForScannedJobs));
1682 createNodesForScannedJobs(Graph, std::move(ScannedJobs),
1683 std::move(ScanResult.InputDepsForScannedJobs));
1684
1685 createRegularEdges(Graph);
1686 pruneUnusedStdlibModuleJobs(Graph, UnusedStdlibModuleJobNodes);
1687 if (!createModuleDependencyEdges(Graph, Diags))
1688 return;
1689 createAndConnectRoot(Graph);
1690
1691 Diags.Report(diag::remark_printing_module_graph);
1692 if (!Diags.isLastDiagnosticIgnored())
1693 llvm::WriteGraph<const CompilationGraph *>(llvm::errs(), &Graph);
1694
1696 feedJobsBackIntoCompilation(C, std::move(Graph));
1697}
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:52
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:216
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:215
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:192
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
Definition Job.h:195
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:232
const char * getExecutable() const
Definition Job.h:230
const std::vector< InputInfo > & getInputInfos() const
Definition Job.h:234
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:3869
ToolChain - Access to tools for a single platform.
Definition ToolChain.h:95
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:287
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:328
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:81
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)