clang 24.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 StringRef DepScanLogPath, 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 Opts.LogPath = DepScanLogPath.str();
649 deps::DependencyScanningService ScanningService(std::move(Opts));
650
651 std::unique_ptr<llvm::ThreadPoolInterface> ThreadPool;
652 std::unique_ptr<ScanningWorkerPool> WorkerPool;
653 std::tie(ThreadPool, WorkerPool) = createOptimalThreadAndWorkerPool(
654 NumScanInputs, HasStdlibModuleInputs, ScanningService);
655
656 StdlibModuleScanScheduler StdlibModuleRegistry(StdlibModuleScanIndexByID);
657 ModuleLookupController LookupController(ModuleCachePath);
658
659 // Scan results are indexed by ScanIndex into ScannableJobIndices, not by
660 // JobIndex into Jobs. This allows one result slot per scannable job.
662 NumScanInputs);
664 NumScanInputs);
665 std::atomic<bool> HasError{false};
666
667 // Scans the job at the given scan index and schedules scans for any newly
668 // discovered Standard library module dependencies.
669 std::function<void(size_t)> ScanOneAndScheduleNew;
670 ScanOneAndScheduleNew = [&](size_t ScanIndex) {
671 const size_t JobIndex = ScannableJobIndices[ScanIndex];
672 const Command &Job = *Jobs[JobIndex];
673 auto [MaybeTUDeps, ScanDiags] = scanDependenciesForJob(
674 Job, *WorkerPool, WorkingDirectory, LookupController);
675
676 // Store diagnostics even for successful scans to also capture any warnings
677 // or notes.
678 assert(AllScanDiags[ScanIndex].empty() &&
679 "Each slot should be written to at most once.");
680 AllScanDiags[ScanIndex] = std::move(ScanDiags);
681
682 if (!MaybeTUDeps) {
683 HasError.store(true, std::memory_order_relaxed);
684 return;
685 }
686
687 // Schedule scans for newly discovered Standard library module dependencies.
688 const auto NewScanInputs = StdlibModuleRegistry.getNewScanInputs(
689 MaybeTUDeps->NamedModuleDeps, getTriple(Job));
690 for (const size_t NewScanIndex : NewScanInputs)
691 ThreadPool->async(
692 [&, NewScanIndex]() { ScanOneAndScheduleNew(NewScanIndex); });
693
694 assert(!AllScanResults[ScanIndex].has_value() &&
695 "Each slot should be written to at most once.");
696 AllScanResults[ScanIndex] = std::move(MaybeTUDeps);
697 };
698
699 // Initiate the scan with all jobs for user-provided inputs.
700 for (const size_t ScanIndex : UserInputScanIndices)
701 ThreadPool->async([&ScanOneAndScheduleNew, ScanIndex]() {
702 ScanOneAndScheduleNew(ScanIndex);
703 });
704 ThreadPool->wait();
705
706 reportAllScanDiagnostics(std::move(AllScanDiags), Diags);
707 if (HasError.load(std::memory_order_relaxed))
708 return std::nullopt;
709
710 // Collect results, mapping scan indices back to job indices.
711 DependencyScanResult Result;
712 for (auto &&[JobIndex, MaybeTUDeps] :
713 llvm::zip_equal(ScannableJobIndices, AllScanResults)) {
714 if (MaybeTUDeps) {
715 Result.ScannedJobIndices.push_back(JobIndex);
716 Result.ModuleDepGraphsForScannedJobs.push_back(
717 std::move(MaybeTUDeps->ModuleGraph));
718 Result.InputDepsForScannedJobs.push_back(
719 makeInputDeps(std::move(*MaybeTUDeps)));
720 } else
721 Result.UnusedStdlibModuleJobIndices.push_back(JobIndex);
722 }
723 Result.NonScannableJobIndices = std::move(NonScannableJobIndices);
724
725#ifndef NDEBUG
726 llvm::SmallDenseSet<size_t> SeenJobIndices;
727 SeenJobIndices.insert_range(Result.ScannedJobIndices);
728 SeenJobIndices.insert_range(Result.UnusedStdlibModuleJobIndices);
729 SeenJobIndices.insert_range(Result.NonScannableJobIndices);
730 assert(llvm::all_of(llvm::index_range(0, Jobs.size()),
731 [&](size_t JobIndex) {
732 return SeenJobIndices.contains(JobIndex);
733 }) &&
734 "Scan result must partition all jobs");
735#endif
736
737 return Result;
738}
739
740namespace {
741class CGNode;
742class CGEdge;
743using CGNodeBase = llvm::DGNode<CGNode, CGEdge>;
744using CGEdgeBase = llvm::DGEdge<CGNode, CGEdge>;
745using CGBase = llvm::DirectedGraph<CGNode, CGEdge>;
746
747/// Compilation Graph Node
748class CGNode : public CGNodeBase {
749public:
750 enum class NodeKind {
751 ClangModuleCC1Job,
752 NamedModuleCC1Job,
753 NonModuleCC1Job,
754 MiscJob,
755 ImageJob,
756 Root,
757 };
758
759 CGNode(const NodeKind K) : Kind(K) {}
760 CGNode(const CGNode &) = delete;
761 CGNode(CGNode &&) = delete;
762 CGNode &operator=(const CGNode &) = delete;
763 CGNode &operator=(CGNode &&) = delete;
764 virtual ~CGNode() = 0;
765
766 NodeKind getKind() const { return Kind; }
767
768private:
769 NodeKind Kind;
770};
771CGNode::~CGNode() = default;
772
773/// Subclass of CGNode representing the root node of the graph.
774///
775/// The root node is a special node that connects to all other nodes with
776/// no incoming edges, so that there is always a path from it to any node
777/// in the graph.
778///
779/// There should only be one such node in a given graph.
780class RootNode : public CGNode {
781public:
782 RootNode() : CGNode(NodeKind::Root) {}
783 ~RootNode() override = default;
784
785 static bool classof(const CGNode *N) {
786 return N->getKind() == NodeKind::Root;
787 }
788};
789
790/// Base class for any CGNode type that represents a job.
791class JobNode : public CGNode {
792public:
793 JobNode(std::unique_ptr<Command> &&Job, NodeKind Kind)
794 : CGNode(Kind), Job(std::move(Job)) {
795 assert(this->Job && "Expected valid job!");
796 }
797 virtual ~JobNode() override = 0;
798
799 std::unique_ptr<Command> Job;
800
801 static bool classof(const CGNode *N) {
802 return N->getKind() != NodeKind::Root;
803 }
804};
805JobNode::~JobNode() = default;
806
807/// Subclass of CGNode representing a -cc1 job which produces a Clang module.
808class ClangModuleJobNode : public JobNode {
809public:
810 ClangModuleJobNode(std::unique_ptr<Command> &&Job, deps::ModuleDeps &&MD)
811 : JobNode(std::move(Job), NodeKind::ClangModuleCC1Job),
812 MD(std::move(MD)) {}
813 ~ClangModuleJobNode() override = default;
814
815 deps::ModuleDeps MD;
816
817 static bool classof(const CGNode *N) {
818 return N->getKind() == NodeKind::ClangModuleCC1Job;
819 }
820};
821
822/// Base class for any CGNode type that represents any scanned -cc1 job.
823class ScannedJobNode : public JobNode {
824public:
825 ScannedJobNode(std::unique_ptr<Command> &&Job, InputDependencies &&InputDeps,
826 NodeKind Kind)
827 : JobNode(std::move(Job), Kind), InputDeps(std::move(InputDeps)) {}
828 ~ScannedJobNode() override = default;
829
830 InputDependencies InputDeps;
831
832 static bool classof(const CGNode *N) {
833 return N->getKind() == NodeKind::NamedModuleCC1Job ||
834 N->getKind() == NodeKind::NonModuleCC1Job;
835 }
836};
837
838/// Subclass of CGNode representing a -cc1 job which produces a C++20 named
839/// module.
840class NamedModuleJobNode : public ScannedJobNode {
841public:
842 NamedModuleJobNode(std::unique_ptr<Command> &&Job,
843 InputDependencies &&InputDeps)
844 : ScannedJobNode(std::move(Job), std::move(InputDeps),
845 NodeKind::NamedModuleCC1Job) {}
846 ~NamedModuleJobNode() override = default;
847
848 static bool classof(const CGNode *N) {
849 return N->getKind() == NodeKind::NamedModuleCC1Job;
850 }
851};
852
853/// Subclass of CGNode representing a -cc1 job which does not produce any
854/// module, but might still have module imports.
855class NonModuleTUJobNode : public ScannedJobNode {
856public:
857 NonModuleTUJobNode(std::unique_ptr<Command> &&Job,
858 InputDependencies &&InputDeps)
859 : ScannedJobNode(std::move(Job), std::move(InputDeps),
860 NodeKind::NonModuleCC1Job) {}
861 ~NonModuleTUJobNode() override = default;
862
863 static bool classof(const CGNode *N) {
864 return N->getKind() == NodeKind::NonModuleCC1Job;
865 }
866};
867
868/// Subclass of CGNode representing a job which produces an image file, such as
869/// a linker or interface stub merge job.
870class ImageJobNode : public JobNode {
871public:
872 ImageJobNode(std::unique_ptr<Command> &&Job)
873 : JobNode(std::move(Job), NodeKind::ImageJob) {}
874 ~ImageJobNode() override = default;
875
876 static bool classof(const CGNode *N) {
877 return N->getKind() == NodeKind::ImageJob;
878 }
879};
880
881/// Subclass of CGNode representing any job not covered by the other node types.
882///
883/// Jobs represented by this node type are not modified by the modules driver.
884class MiscJobNode : public JobNode {
885public:
886 MiscJobNode(std::unique_ptr<Command> &&Job)
887 : JobNode(std::move(Job), NodeKind::MiscJob) {}
888 ~MiscJobNode() override = default;
889
890 static bool classof(const CGNode *N) {
891 return N->getKind() == NodeKind::MiscJob;
892 }
893};
894
895/// Compilation Graph Edge
896///
897/// Edges connect the producer of an output to its consumer, except for edges
898/// stemming from the root node.
899class CGEdge : public CGEdgeBase {
900public:
901 enum class EdgeKind {
902 Regular,
903 ModuleDependency,
904 Rooted,
905 };
906
907 CGEdge(CGNode &N, EdgeKind K) : CGEdgeBase(N), Kind(K) {}
908 CGEdge(const CGEdge &) = delete;
909 CGEdge &operator=(const CGEdge &) = delete;
910 CGEdge(CGEdge &&) = delete;
911 CGEdge &operator=(CGEdge &&) = delete;
912
913 EdgeKind getKind() const { return Kind; }
914
915private:
916 EdgeKind Kind;
917};
918
919/// Compilation Graph
920///
921/// The graph owns all of its components.
922/// All nodes and edges created by the graph have the same livetime as the
923/// graph, even if removed from the graph's node list.
924class CompilationGraph : public CGBase {
925public:
926 CompilationGraph() = default;
927 CompilationGraph(const CompilationGraph &) = delete;
928 CompilationGraph &operator=(const CompilationGraph &) = delete;
929 CompilationGraph(CompilationGraph &&G) = default;
930 CompilationGraph &operator=(CompilationGraph &&) = default;
931 ~CompilationGraph() = default;
932
933 CGNode &getRoot() const {
934 assert(Root && "Root node has not yet been created!");
935 return *Root;
936 }
937
938 RootNode &createRoot() {
939 assert(!Root && "Root node has already been created!");
940 auto &RootRef = createNodeImpl<RootNode>();
941 Root = &RootRef;
942 return RootRef;
943 }
944
945 template <typename T, typename... Args> T &createJobNode(Args &&...Arg) {
946 static_assert(std::is_base_of<JobNode, T>::value,
947 "T must be derived from JobNode");
948 return createNodeImpl<T>(std::forward<Args>(Arg)...);
949 }
950
951 CGEdge &createEdge(CGEdge::EdgeKind Kind, CGNode &Src, CGNode &Dst) {
952 auto Edge = std::make_unique<CGEdge>(Dst, Kind);
953 CGEdge &EdgeRef = *Edge;
954 AllEdges.push_back(std::move(Edge));
955 connect(Src, Dst, EdgeRef);
956 return EdgeRef;
957 }
958
959private:
960 using CGBase::addNode;
961 using CGBase::connect;
962
963 template <typename T, typename... Args> T &createNodeImpl(Args &&...Arg) {
964 auto Node = std::make_unique<T>(std::forward<Args>(Arg)...);
965 T &NodeRef = *Node;
966 AllNodes.push_back(std::move(Node));
967 addNode(NodeRef);
968 return NodeRef;
969 }
970
971 CGNode *Root = nullptr;
972 SmallVector<std::unique_ptr<CGNode>> AllNodes;
973 SmallVector<std::unique_ptr<CGEdge>> AllEdges;
974};
975} // anonymous namespace
976
977static StringRef getFirstInputFilename(const Command &Job) {
978 return Job.getInputInfos().front().getFilename();
979}
980
981namespace llvm {
982/// Non-const versions of the GraphTraits specializations for CompilationGraph.
983template <> struct GraphTraits<CGNode *> {
984 using NodeRef = CGNode *;
985
986 static NodeRef CGGetTargetNode(CGEdge *E) { return &E->getTargetNode(); }
987
989 mapped_iterator<CGNode::iterator, decltype(&CGGetTargetNode)>;
990 using ChildEdgeIteratorType = CGNode::iterator;
991
992 static NodeRef getEntryNode(NodeRef N) { return N; }
993
995 return ChildIteratorType(N->begin(), &CGGetTargetNode);
996 }
997
999 return ChildIteratorType(N->end(), &CGGetTargetNode);
1000 }
1001
1003 return N->begin();
1004 }
1005 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
1006};
1007
1008template <> struct GraphTraits<CompilationGraph *> : GraphTraits<CGNode *> {
1009 using GraphRef = CompilationGraph *;
1010 using NodeRef = CGNode *;
1011
1012 using nodes_iterator = CompilationGraph::iterator;
1013
1014 static NodeRef getEntryNode(GraphRef G) { return &G->getRoot(); }
1015
1016 static nodes_iterator nodes_begin(GraphRef G) { return G->begin(); }
1017
1018 static nodes_iterator nodes_end(GraphRef G) { return G->end(); }
1019};
1020
1021/// Const versions of the GraphTraits specializations for CompilationGraph.
1022template <> struct GraphTraits<const CGNode *> {
1023 using NodeRef = const CGNode *;
1024
1025 static NodeRef CGGetTargetNode(const CGEdge *E) {
1026 return &E->getTargetNode();
1027 }
1028
1030 mapped_iterator<CGNode::const_iterator, decltype(&CGGetTargetNode)>;
1031 using ChildEdgeIteratorType = CGNode::const_iterator;
1032
1033 static NodeRef getEntryNode(NodeRef N) { return N; }
1034
1036 return ChildIteratorType(N->begin(), &CGGetTargetNode);
1037 }
1038
1040 return ChildIteratorType(N->end(), &CGGetTargetNode);
1041 }
1042
1044 return N->begin();
1045 }
1046
1047 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
1048};
1049
1050template <>
1051struct GraphTraits<const CompilationGraph *> : GraphTraits<const CGNode *> {
1052 using GraphRef = const CompilationGraph *;
1053 using NodeRef = const CGNode *;
1054
1055 using nodes_iterator = CompilationGraph::const_iterator;
1056
1057 static NodeRef getEntryNode(GraphRef G) { return &G->getRoot(); }
1058
1059 static nodes_iterator nodes_begin(GraphRef G) { return G->begin(); }
1060
1061 static nodes_iterator nodes_end(GraphRef G) { return G->end(); }
1062};
1063
1064template <>
1065struct DOTGraphTraits<const CompilationGraph *> : DefaultDOTGraphTraits {
1066 explicit DOTGraphTraits(bool IsSimple = false)
1067 : DefaultDOTGraphTraits(IsSimple) {}
1068 using GraphRef = const CompilationGraph *;
1069 using NodeRef = const CGNode *;
1070
1071 static std::string getGraphName(GraphRef) {
1072 return "Module Dependency Graph";
1073 }
1074
1075 static std::string getGraphProperties(GraphRef) {
1076 return "\tnode [shape=Mrecord, colorscheme=set23, style=filled];\n";
1077 }
1078
1079 static bool renderGraphFromBottomUp() { return true; }
1080
1082 // Only show nodes with module dependency relations.
1084 }
1085
1086 static std::string getNodeIdentifier(NodeRef N, GraphRef) {
1087 return llvm::TypeSwitch<NodeRef, std::string>(N)
1088 .Case([](const ClangModuleJobNode *ClangModuleNode) {
1089 const auto &ID = ClangModuleNode->MD.ID;
1090 return llvm::formatv("{0}-{1}", ID.ModuleName, ID.ContextHash).str();
1091 })
1092 .Case([](const NamedModuleJobNode *NamedModuleNode) {
1093 return llvm::formatv("{0}-{1}", NamedModuleNode->InputDeps.ModuleName,
1094 getTriple(*NamedModuleNode->Job))
1095 .str();
1096 })
1097 .Case([](const NonModuleTUJobNode *NonModuleTUNode) {
1098 const auto &Job = *NonModuleTUNode->Job;
1099 return llvm::formatv("{0}-{1}", getFirstInputFilename(Job),
1100 getTriple(Job))
1101 .str();
1102 })
1103 .DefaultUnreachable("Unexpected node kind! Is this node hidden?");
1104 }
1105
1106 static std::string getNodeLabel(NodeRef N, GraphRef) {
1107 return llvm::TypeSwitch<NodeRef, std::string>(N)
1108 .Case([](const ClangModuleJobNode *ClangModuleNode) {
1109 const auto &ID = ClangModuleNode->MD.ID;
1110 return llvm::formatv("Module type: Clang module \\| Module name: {0} "
1111 "\\| Hash: {1}",
1112 ID.ModuleName, ID.ContextHash)
1113 .str();
1114 })
1115 .Case([](const NamedModuleJobNode *NamedModuleNode) {
1116 const auto &Job = *NamedModuleNode->Job;
1117 return llvm::formatv(
1118 "Filename: {0} \\| Module type: Named module \\| "
1119 "Module name: {1} \\| Triple: {2}",
1121 NamedModuleNode->InputDeps.ModuleName, getTriple(Job))
1122 .str();
1123 })
1124 .Case([](const NonModuleTUJobNode *NonModuleTUNode) {
1125 const auto &Job = *NonModuleTUNode->Job;
1126 return llvm::formatv("Filename: {0} \\| Triple: {1}",
1128 .str();
1129 })
1130 .DefaultUnreachable("Unexpected node kind! Is this node hidden?");
1131 }
1132
1133 static std::string getNodeAttributes(NodeRef N, GraphRef) {
1134 switch (N->getKind()) {
1135 case CGNode::NodeKind::ClangModuleCC1Job:
1136 return "fillcolor=1";
1137 case CGNode::NodeKind::NamedModuleCC1Job:
1138 return "fillcolor=2";
1139 case CGNode::NodeKind::NonModuleCC1Job:
1140 return "fillcolor=3";
1141 default:
1142 llvm_unreachable("Unexpected node kind! Is this node hidden?");
1143 }
1144 }
1145};
1146
1147/// GraphWriter specialization for CompilationGraph that emits a more
1148/// human-readable DOT graph.
1149template <>
1150class GraphWriter<const CompilationGraph *>
1151 : public GraphWriterBase<const CompilationGraph *,
1153public:
1154 using GraphType = const CompilationGraph *;
1156
1157 GraphWriter(llvm::raw_ostream &O, const GraphType &G, bool IsSimple)
1158 : Base(O, G, IsSimple), EscapedIDByNodeRef(G->size()) {}
1159
1160 void writeNodes() {
1161 auto IsNodeVisible = [&](NodeRef N) { return !DTraits.isNodeHidden(N, G); };
1162 auto VisibleNodes = llvm::filter_to_vector(nodes(G), IsNodeVisible);
1163
1164 writeNodeDefinitions(VisibleNodes);
1165 O << "\n";
1166 writeNodeRelations(VisibleNodes);
1167 }
1168
1169private:
1170 using Base::DOTTraits;
1171 using Base::GTraits;
1172 using Base::NodeRef;
1173
1174 void writeNodeDefinitions(ArrayRef<NodeRef> VisibleNodes) {
1175 for (NodeRef Node : VisibleNodes) {
1176 std::string EscapedNodeID =
1177 DOT::EscapeString(DTraits.getNodeIdentifier(Node, G));
1178 const std::string NodeLabel = DTraits.getNodeLabel(Node, G);
1179 const std::string NodeAttrs = DTraits.getNodeAttributes(Node, G);
1180 O << '\t' << '"' << EscapedNodeID << "\" [" << NodeAttrs << ", label=\"{ "
1181 << DOT::EscapeString(NodeLabel) << " }\"];\n";
1182 EscapedIDByNodeRef.try_emplace(Node, std::move(EscapedNodeID));
1183 }
1184 }
1185
1186 void writeNodeRelations(ArrayRef<NodeRef> VisibleNodes) {
1187 auto IsNodeVisible = [&](NodeRef N) { return !DTraits.isNodeHidden(N, G); };
1188 for (NodeRef Node : VisibleNodes) {
1189 auto DstNodes = llvm::make_range(GTraits::child_begin(Node),
1190 GTraits::child_end(Node));
1191 auto VisibleDstNodes = llvm::make_filter_range(DstNodes, IsNodeVisible);
1192 StringRef EscapedSrcNodeID = EscapedIDByNodeRef.at(Node);
1193 for (NodeRef DstNode : VisibleDstNodes) {
1194 StringRef EscapedTgtNodeID = EscapedIDByNodeRef.at(DstNode);
1195 O << '\t' << '"' << EscapedSrcNodeID << "\" -> \"" << EscapedTgtNodeID
1196 << "\";\n";
1197 }
1198 }
1199 }
1200
1201 DenseMap<NodeRef, std::string> EscapedIDByNodeRef;
1202};
1203} // namespace llvm
1204
1205/// Validates that each module-defining source is of type \c TY_CXXModule.
1206///
1207/// \returns false on error, with diagnostics emitted via \p Diags.
1209 ArrayRef<std::unique_ptr<Command>> ScannedJobs,
1210 ArrayRef<InputDependencies> InputDepsForScannedJobs,
1211 DiagnosticsEngine &Diags) {
1212 for (const auto &&[Job, InputDeps] : llvm::zip_equal(
1213 llvm::make_pointee_range(ScannedJobs), InputDepsForScannedJobs)) {
1214 const auto &MainInput = Job.getInputInfos().front();
1215 const bool DefinesNamedModule = !InputDeps.ModuleName.empty();
1216
1217 if (DefinesNamedModule && MainInput.getType() != types::TY_CXXModule &&
1218 MainInput.getType() != types::TY_CXXStdModule) {
1219 Diags.Report(diag::err_module_defined_outside_of_module_source)
1220 << InputDeps.ModuleName << MainInput.getFilename();
1221 return false;
1222 }
1223 }
1224 return true;
1225}
1226
1228takeJobsAtIndices(SmallVectorImpl<std::unique_ptr<Command>> &Jobs,
1229 ArrayRef<size_t> Indices) {
1231 for (const auto JobIndex : Indices) {
1232 assert(Jobs[JobIndex] && "Expected valid job!");
1233 Out.push_back(std::move(Jobs[JobIndex]));
1234 }
1235 return Out;
1236}
1237
1238/// Creates nodes for all jobs that could not be scanned (e.g. image jobs, ...).
1240 CompilationGraph &Graph,
1241 SmallVectorImpl<std::unique_ptr<Command>> &&NonScannableJobs) {
1242 for (auto &Job : NonScannableJobs) {
1243 if (Job->getCreator().isLinkJob())
1244 Graph.createJobNode<ImageJobNode>(std::move(Job));
1245 else
1246 Graph.createJobNode<MiscJobNode>(std::move(Job));
1247 }
1248}
1249
1250/// Creates nodes for the Standard library module jobs not discovered as
1251/// dependencies.
1252///
1253/// These and any dependent (non-image) job nodes should be pruned from the
1254/// graph later.
1256 CompilationGraph &Graph,
1257 SmallVectorImpl<std::unique_ptr<Command>> &&UnusedStdlibModuleJobs) {
1258 SmallVector<JobNode *> StdlibModuleNodesToPrune;
1259 for (auto &Job : UnusedStdlibModuleJobs) {
1260 auto &NewNode = Graph.createJobNode<MiscJobNode>(std::move(Job));
1261 StdlibModuleNodesToPrune.push_back(&NewNode);
1262 }
1263 return StdlibModuleNodesToPrune;
1264}
1265
1266// Returns the derived argument list for the tool chain responsible
1267// for creating \p Job.
1268static const DerivedArgList &getToolChainArgs(Compilation &C,
1269 const Command &Job) {
1270 const auto &TC = Job.getCreator().getToolChain();
1271 const auto &SourceAction = Job.getSource();
1272 return C.getArgsForToolChain(&TC, SourceAction.getOffloadingArch(),
1273 SourceAction.getOffloadingDeviceKind());
1274}
1275
1276/// Creates a job for the Clang module described by \p MD.
1277static std::unique_ptr<Command>
1279 const deps::ModuleDeps &MD) {
1280 DerivedArgList &Args = C.getArgs();
1281 const OptTable &Opts = C.getDriver().getOpts();
1282 Arg *InputArg = makeInputArg(Args, Opts, "<discovered clang module>");
1283 Action *IA = C.MakeAction<InputAction>(*InputArg, types::ID::TY_ModuleFile);
1284 Action *PA = C.MakeAction<PrecompileJobAction>(IA, types::ID::TY_ModuleFile);
1285 PA->propagateOffloadInfo(&ImportingJob.getSource());
1286
1287 const auto &TCArgs = getToolChainArgs(C, ImportingJob);
1288
1289 const auto &BuildArgs = MD.getBuildArguments();
1290 ArgStringList JobArgs;
1291 JobArgs.reserve(BuildArgs.size());
1292 for (const auto &Arg : BuildArgs)
1293 JobArgs.push_back(TCArgs.MakeArgString(Arg));
1294
1295 const auto &D = C.getDriver();
1296 return std::make_unique<Command>(
1297 *PA, ImportingJob.getCreator(), ResponseFileSupport::AtFileUTF8(),
1298 D.getDriverProgramPath(), JobArgs,
1299 /*Inputs=*/ArrayRef<InputInfo>{},
1300 /*Outputs=*/ArrayRef<InputInfo>{}, D.getPrependArg());
1301}
1302
1303/// Creates a \c ClangModuleJobNode with associated job for each unique Clang
1304/// module in \p ModuleDepGraphsForScannedJobs.
1305///
1306/// \param ImportingJobs Jobs whose module dependencies were scanned.
1307/// \param ModuleDepGraphsForScannedJobs Full Clang module dependency graphs
1308/// corresponding to \p ImportingJobs, in order.
1310 CompilationGraph &Graph, Compilation &C,
1311 ArrayRef<std::unique_ptr<Command>> ImportingJobs,
1312 SmallVectorImpl<deps::ModuleDepsGraph> &&ModuleDepGraphsForScannedJobs) {
1313 llvm::DenseSet<deps::ModuleID> AlreadySeen;
1314 for (auto &&[ImportingJob, ModuleDepsGraph] :
1315 llvm::zip_equal(llvm::make_pointee_range(ImportingJobs),
1316 ModuleDepGraphsForScannedJobs)) {
1317 for (auto &MD : ModuleDepsGraph) {
1318 const auto Inserted = AlreadySeen.insert(MD.ID).second;
1319 if (!Inserted)
1320 continue;
1321
1322 auto ClangModuleJob = createClangModulePrecompileJob(C, ImportingJob, MD);
1323 Graph.createJobNode<ClangModuleJobNode>(std::move(ClangModuleJob),
1324 std::move(MD));
1325 }
1326 }
1327}
1328
1329/// Installs the command lines produced by the dependency scan into
1330/// \p ScannedJobs.
1331static void
1333 MutableArrayRef<std::unique_ptr<Command>> ScannedJobs,
1334 ArrayRef<InputDependencies> InputDepsForScannedJobs) {
1335 for (auto &&[Job, InputDeps] : llvm::zip_equal(
1336 llvm::make_pointee_range(ScannedJobs), InputDepsForScannedJobs)) {
1337 const auto &BuildArgs = InputDeps.BuildArgs;
1338 ArgStringList JobArgs;
1339 JobArgs.reserve(BuildArgs.size());
1340
1341 auto &TCArgs = getToolChainArgs(C, Job);
1342 for (const auto &Arg : BuildArgs)
1343 JobArgs.push_back(TCArgs.MakeArgString(Arg));
1344
1345 Job.replaceArguments(std::move(JobArgs));
1346 }
1347}
1348
1349/// Creates nodes for all jobs which were scanned for dependencies.
1350///
1351/// The updated command lines produced by the dependency scan are installed at a
1352/// later point.
1354 CompilationGraph &Graph,
1355 SmallVectorImpl<std::unique_ptr<Command>> &&ScannedJobs,
1356 SmallVectorImpl<InputDependencies> &&InputDepsForScannedJobs) {
1357 for (auto &&[Job, InputDeps] :
1358 llvm::zip_equal(ScannedJobs, InputDepsForScannedJobs)) {
1359 if (InputDeps.ModuleName.empty())
1360 Graph.createJobNode<NonModuleTUJobNode>(std::move(Job),
1361 std::move(InputDeps));
1362 else
1363 Graph.createJobNode<NamedModuleJobNode>(std::move(Job),
1364 std::move(InputDeps));
1365 }
1366}
1367
1368template <typename LookupT, typename KeyRangeT>
1369static void connectEdgesViaLookup(CompilationGraph &Graph, CGNode &TgtNode,
1370 const LookupT &SrcNodeLookup,
1371 const KeyRangeT &SrcNodeLookupKeys,
1372 CGEdge::EdgeKind Kind) {
1373 for (const auto &Key : SrcNodeLookupKeys) {
1374 const auto It = SrcNodeLookup.find(Key);
1375 if (It == SrcNodeLookup.end())
1376 continue;
1377
1378 auto &SrcNode = *It->second;
1379 Graph.createEdge(Kind, SrcNode, TgtNode);
1380 }
1381}
1382
1383/// Create edges for regular (non-module) dependencies in \p Graph.
1384static void createRegularEdges(CompilationGraph &Graph) {
1385 llvm::DenseMap<StringRef, CGNode *> NodeByOutputFiles;
1386 for (auto *Node : Graph) {
1387 for (const auto &Output : cast<JobNode>(Node)->Job->getOutputFilenames()) {
1388 [[maybe_unused]] const bool Inserted =
1389 NodeByOutputFiles.try_emplace(Output, Node).second;
1390 assert(Inserted &&
1391 "Driver should not produce multiple jobs with identical outputs!");
1392 }
1393 }
1394
1395 for (auto *Node : Graph) {
1396 const auto &InputInfos = cast<JobNode>(Node)->Job->getInputInfos();
1397 auto InputFilenames = llvm::map_range(
1398 InputInfos, [](const auto &II) { return II.getFilename(); });
1399
1400 connectEdgesViaLookup(Graph, *Node, NodeByOutputFiles, InputFilenames,
1401 CGEdge::EdgeKind::Regular);
1402 }
1403}
1404
1405/// Create edges for module dependencies in \p Graph.
1406///
1407/// \returns false if there are multiple definitions for a named module, with
1408/// diagnostics reported to \p Diags; otherwise returns true.
1409static bool createModuleDependencyEdges(CompilationGraph &Graph,
1410 DiagnosticsEngine &Diags) {
1411 llvm::DenseMap<deps::ModuleID, CGNode *> ClangModuleNodeByID;
1412 llvm::DenseMap<ModuleNameAndTriple, CGNode *> NamedModuleNodeByID;
1413
1414 // Map each module to the job that produces it.
1415 bool HasDuplicateModuleError = false;
1416 for (auto *Node : Graph) {
1417 llvm::TypeSwitch<CGNode *>(Node)
1418 .Case([&](ClangModuleJobNode *ClangModuleNode) {
1419 [[maybe_unused]] const bool Inserted =
1420 ClangModuleNodeByID.try_emplace(ClangModuleNode->MD.ID, Node)
1421 .second;
1422 assert(Inserted &&
1423 "Multiple Clang module nodes with the same module ID!");
1424 })
1425 .Case([&](NamedModuleJobNode *NamedModuleNode) {
1426 StringRef ModuleName = NamedModuleNode->InputDeps.ModuleName;
1427 ModuleNameAndTriple ID{ModuleName, getTriple(*NamedModuleNode->Job)};
1428 const auto [It, Inserted] = NamedModuleNodeByID.try_emplace(ID, Node);
1429 if (!Inserted) {
1430 // For scan input jobs, their first input is always a filename and
1431 // the scanned source.
1432 // We don't use InputDeps.FileDeps here because diagnostics should
1433 // refer to the filename as specified on the command line, not the
1434 // canonical absolute path.
1435 StringRef PrevFile =
1436 getFirstInputFilename(*cast<JobNode>(It->second)->Job);
1437 StringRef CurFile = getFirstInputFilename(*NamedModuleNode->Job);
1438 Diags.Report(diag::err_modules_driver_named_module_redefinition)
1439 << ModuleName << PrevFile << CurFile;
1440 HasDuplicateModuleError = true;
1441 }
1442 });
1443 }
1444 if (HasDuplicateModuleError)
1445 return false;
1446
1447 // Create edges from the module nodes to their importers.
1448 for (auto *Node : Graph) {
1449 llvm::TypeSwitch<CGNode *>(Node)
1450 .Case([&](ClangModuleJobNode *ClangModuleNode) {
1451 connectEdgesViaLookup(Graph, *ClangModuleNode, ClangModuleNodeByID,
1452 ClangModuleNode->MD.ClangModuleDeps,
1453 CGEdge::EdgeKind::ModuleDependency);
1454 })
1455 .Case([&](ScannedJobNode *NodeWithInputDeps) {
1456 connectEdgesViaLookup(Graph, *NodeWithInputDeps, ClangModuleNodeByID,
1457 NodeWithInputDeps->InputDeps.ClangModuleDeps,
1458 CGEdge::EdgeKind::ModuleDependency);
1459
1460 StringRef Triple = getTriple(*NodeWithInputDeps->Job);
1461 const auto NamedModuleDepIDs =
1462 llvm::map_range(NodeWithInputDeps->InputDeps.NamedModuleDeps,
1463 [&](StringRef ModuleName) {
1464 return ModuleNameAndTriple{ModuleName, Triple};
1465 });
1466 connectEdgesViaLookup(Graph, *NodeWithInputDeps, NamedModuleNodeByID,
1467 NamedModuleDepIDs,
1468 CGEdge::EdgeKind::ModuleDependency);
1469 });
1470 }
1471
1472 return true;
1473}
1474
1475/// Prunes the compilation graph of any jobs which build Standard library
1476/// modules not required in this compilation.
1477static void
1478pruneUnusedStdlibModuleJobs(CompilationGraph &Graph,
1479 ArrayRef<JobNode *> UnusedStdlibModuleJobNodes) {
1480 // Collect all reachable non-image job nodes.
1481 llvm::SmallPtrSet<JobNode *, 16> PrunableJobNodes;
1482 for (auto *PrunableJobNodeRoot : UnusedStdlibModuleJobNodes) {
1483 auto ReachableJobNodes =
1484 llvm::map_range(llvm::depth_first(cast<CGNode>(PrunableJobNodeRoot)),
1485 llvm::CastTo<JobNode>);
1486 auto ReachableNonImageNodes = llvm::make_filter_range(
1487 ReachableJobNodes, [](auto *N) { return !llvm::isa<ImageJobNode>(N); });
1488 PrunableJobNodes.insert_range(ReachableNonImageNodes);
1489 }
1490
1491 // Map image job nodes to the prunable job nodes that feed into them.
1492 llvm::DenseMap<ImageJobNode *, llvm::SmallPtrSet<JobNode *, 4>>
1493 PrunableJobNodesByImageNode;
1494 for (auto *PrunableJobNode : PrunableJobNodes) {
1495 auto ReachableJobNodes = llvm::depth_first(cast<CGNode>(PrunableJobNode));
1496 auto ReachableImageJobNodes = llvm::map_range(
1497 llvm::make_filter_range(ReachableJobNodes, llvm::IsaPred<ImageJobNode>),
1498 llvm::CastTo<ImageJobNode>);
1499
1500 for (auto *ImageNode : ReachableImageJobNodes)
1501 PrunableJobNodesByImageNode[ImageNode].insert(PrunableJobNode);
1502 }
1503
1504 // Remove from each affected image job node any arguments corresponding to
1505 // outputs of the connected prunable job nodes.
1506 for (auto &[ImageNode, PrunableJobNodeInputs] : PrunableJobNodesByImageNode) {
1507 SmallVector<StringRef, 4> OutputsToRemove;
1508 for (auto *JN : PrunableJobNodeInputs)
1509 llvm::append_range(OutputsToRemove, JN->Job->getOutputFilenames());
1510
1511 auto NewArgs = ImageNode->Job->getArguments();
1512 llvm::erase_if(NewArgs, [&](StringRef Arg) {
1513 return llvm::is_contained(OutputsToRemove, Arg);
1514 });
1515 ImageNode->Job->replaceArguments(NewArgs);
1516 }
1517
1518 // Erase all prunable job nodes from the graph.
1519 for (auto *JN : PrunableJobNodes) {
1520 // Nodes are owned by the graph, but we can release the associated job.
1521 JN->Job.reset();
1522 Graph.removeNode(*JN);
1523 }
1524}
1525
1526/// Creates the root node and connects it to all nodes with no incoming edges
1527/// ensuring that every node in the graph is reachable from the root.
1528static void createAndConnectRoot(CompilationGraph &Graph) {
1529 llvm::SmallPtrSet<CGNode *, 16> HasIncomingEdge;
1530 for (auto *Node : Graph)
1531 for (auto *Edge : Node->getEdges())
1532 HasIncomingEdge.insert(&Edge->getTargetNode());
1533
1534 auto AllNonRootNodes = llvm::iterator_range(Graph);
1535 auto &Root = Graph.createRoot();
1536
1537 for (auto *Node : AllNonRootNodes) {
1538 if (HasIncomingEdge.contains(Node))
1539 continue;
1540 Graph.createEdge(CGEdge::EdgeKind::Rooted, Root, *Node);
1541 }
1542}
1543
1544/// Creates a temporary output path for \p ModuleName.
1545static std::string createModuleOutputPath(const Compilation &C,
1546 StringRef ModuleName) {
1547 // Sanitize the ':' included in parition names. It is illegal for filenames on
1548 // Windows.
1549 SmallString<32> SanitizedModuleName(ModuleName);
1550 llvm::replace(SanitizedModuleName, ':', '-');
1551 auto ModuleOutputPath = C.getDriver().GetTemporaryPath(
1552 SanitizedModuleName, types::getTypeTempSuffix(types::TY_ModuleFile));
1553 return ModuleOutputPath;
1554}
1555
1556/// Adds the '-fmodule-output=' argument for the module produced by \p Node.
1558 NamedModuleJobNode &Node,
1559 StringRef ModuleOutputPath) {
1560 auto &Job = *Node.Job;
1561 const auto &TCArgs = getToolChainArgs(C, Job);
1562 auto JobArgs = Job.getArguments();
1563 JobArgs.push_back(
1564 TCArgs.MakeArgString("-fmodule-output=" + ModuleOutputPath));
1565 Job.replaceArguments(std::move(JobArgs));
1566}
1567
1568/// Propagates the '-fmodule-file=' mapping for the named module described by
1569/// \p Node to each dependent job.
1571 NamedModuleJobNode &Node,
1572 StringRef ModuleOutputPath) {
1573 const StringRef ModuleName = Node.InputDeps.ModuleName;
1574
1575 auto DependentNodes = llvm::drop_begin(llvm::depth_first<CGNode *>(&Node));
1576 auto DependentScannedNodes = llvm::map_range(
1577 llvm::make_filter_range(DependentNodes, llvm::IsaPred<ScannedJobNode>),
1578 llvm::CastTo<ScannedJobNode>);
1579
1580 for (ScannedJobNode *DependentNode : DependentScannedNodes) {
1581 auto &DependentJob = *DependentNode->Job;
1582 const auto &TCArgs = getToolChainArgs(C, DependentJob);
1583 auto JobArgs = DependentJob.getArguments();
1584 JobArgs.push_back(TCArgs.MakeArgString("-fmodule-file=" + ModuleName + "=" +
1585 ModuleOutputPath));
1586 DependentJob.replaceArguments(std::move(JobArgs));
1587 }
1588}
1589
1590/// Finalizes command lines for C++20 named module dependencies.
1591///
1592/// The command lines produced by dependency scanning are only adjusted to
1593/// handle discovered Clang modules. For C++20 named modules, we update the
1594/// command-lines here.
1596 CompilationGraph &Graph) {
1597 const auto NamedModuleNodes = llvm::map_range(
1598 llvm::make_filter_range(Graph, llvm::IsaPred<NamedModuleJobNode>),
1599 llvm::CastTo<NamedModuleJobNode>);
1600
1601 for (NamedModuleJobNode *Node : NamedModuleNodes) {
1602 const auto &Job = *Node->Job;
1603
1604 // For Standard library modules, the driver already creates the module
1605 // output as a temp file, so we can use that path directly.
1606 const bool IsStdModule =
1607 Job.getInputInfos().front().getType() == types::TY_CXXStdModule;
1608 if (IsStdModule) {
1609 StringRef ModuleOutputPath = Job.getOutputFilenames().front();
1610 propagateModuleFileMappingArg(C, *Node, ModuleOutputPath);
1611 continue;
1612 }
1613
1614 const StringRef ModuleName = Node->InputDeps.ModuleName;
1615 const auto ModuleOutputPath = createModuleOutputPath(C, ModuleName);
1616 C.addTempFile(C.getArgs().MakeArgString(ModuleOutputPath));
1617
1618 configureNamedModuleOutputArg(C, *Node, ModuleOutputPath);
1619 propagateModuleFileMappingArg(C, *Node, ModuleOutputPath);
1620 }
1621}
1622
1623/// Moves jobs from \p Graph into \p C in the graph's topological order.
1625 CompilationGraph &&Graph) {
1626 llvm::ReversePostOrderTraversal<CompilationGraph *> TopologicallySortedNodes(
1627 &Graph);
1628 assert(isa<RootNode>(*TopologicallySortedNodes.begin()) &&
1629 "First node in topological order must be the root!");
1630 auto TopologicallySortedJobNodes = llvm::map_range(
1631 llvm::drop_begin(TopologicallySortedNodes), llvm::CastTo<JobNode>);
1632 for (auto *JN : TopologicallySortedJobNodes)
1633 C.addCommand(std::move(JN->Job));
1634}
1635
1638 llvm::PrettyStackTraceString CrashInfo("Running modules driver.");
1639
1640 auto Jobs = C.getJobs().takeJobs();
1641
1642 const auto ManifestEntryBySource = buildManifestLookupMap(ManifestEntries);
1643 // Apply manifest-entry specific command-line modifications before the scan as
1644 // they might affect it.
1645 applyArgsForStdModuleManifestInputs(C, ManifestEntryBySource, Jobs);
1646
1647 DiagnosticsEngine &Diags = C.getDriver().getDiags();
1648
1649 // Run the dependency scan.
1650 const auto MaybeModuleCachePath = getModuleCachePath(C.getArgs());
1651 if (!MaybeModuleCachePath) {
1652 Diags.Report(diag::err_default_modules_cache_not_available);
1653 return;
1654 }
1655
1656 auto MaybeCWD = C.getDriver().getVFS().getCurrentWorkingDirectory();
1657 const auto CWD = MaybeCWD ? std::move(*MaybeCWD) : ".";
1658
1659 const llvm::opt::Arg *LogPathArg =
1660 C.getArgs().getLastArg(options::OPT_fdepscan_log_path);
1661 StringRef DepScanLogPath =
1662 LogPathArg ? StringRef(LogPathArg->getValue()).trim() : StringRef();
1663 if (LogPathArg && DepScanLogPath.empty()) {
1664 Diags.Report(diag::err_drv_depscan_log_path_empty);
1665 return;
1666 }
1667
1668 auto MaybeScanResults =
1669 scanDependencies(Jobs, ManifestEntryBySource, *MaybeModuleCachePath, CWD,
1670 DepScanLogPath, Diags);
1671 if (!MaybeScanResults) {
1672 Diags.Report(diag::err_dependency_scan_failed);
1673 return;
1674 }
1675 auto &ScanResult = *MaybeScanResults;
1676
1677 // Build the compilation graph.
1678 CompilationGraph Graph;
1680 Graph, takeJobsAtIndices(Jobs, ScanResult.NonScannableJobIndices));
1681 auto UnusedStdlibModuleJobNodes = createNodesForUnusedStdlibModuleJobs(
1682 Graph, takeJobsAtIndices(Jobs, ScanResult.UnusedStdlibModuleJobIndices));
1683
1684 auto ScannedJobs = takeJobsAtIndices(Jobs, ScanResult.ScannedJobIndices);
1685 if (!validateScannedJobInputKinds(ScannedJobs,
1686 ScanResult.InputDepsForScannedJobs, Diags))
1687 return;
1688 installScanCommandLines(C, ScannedJobs, ScanResult.InputDepsForScannedJobs);
1689
1691 Graph, C, /*ImportingJobs*/ ScannedJobs,
1692 std::move(ScanResult.ModuleDepGraphsForScannedJobs));
1693 createNodesForScannedJobs(Graph, std::move(ScannedJobs),
1694 std::move(ScanResult.InputDepsForScannedJobs));
1695
1696 createRegularEdges(Graph);
1697 pruneUnusedStdlibModuleJobs(Graph, UnusedStdlibModuleJobNodes);
1698 if (!createModuleDependencyEdges(Graph, Diags))
1699 return;
1700 createAndConnectRoot(Graph);
1701
1702 Diags.Report(diag::remark_printing_module_graph);
1703 if (!Diags.isLastDiagnosticIgnored())
1704 llvm::WriteGraph<const CompilationGraph *>(llvm::errs(), &Graph);
1705
1707 feedJobsBackIntoCompilation(C, std::move(Graph));
1708}
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::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::optional< DependencyScanResult > scanDependencies(ArrayRef< std::unique_ptr< Command > > Jobs, llvm::DenseMap< StringRef, const StdModuleManifest::Module * > ManifestLookup, StringRef ModuleCachePath, StringRef WorkingDirectory, StringRef DepScanLogPath, DiagnosticsEngine &Diags)
Scans the compilations job list Jobs for module 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:232
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasSourceManager() const
Definition Diagnostic.h:633
bool isLastDiagnosticIgnored() const
Determine whether the previous diagnostic was ignored.
Definition Diagnostic.h:820
SourceManager & getSourceManager() const
Definition Diagnostic.h:635
Level
The level of the diagnostic, after it has been through mapping.
Definition Diagnostic.h:237
DiagnosticConsumer * getClient()
Definition Diagnostic.h:623
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:57
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:48
BoundArch 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:91
OffloadKind getOffloadingDeviceKind() const
Definition Action.h:215
Command - An executable path/name and argument vector to execute.
Definition Job.h:107
const Action & getSource() const
getSource - Return the Action which caused the creation of this job.
Definition Job.h:196
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
Definition Job.h:199
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:243
const char * getExecutable() const
Definition Job.h:241
const std::vector< InputInfo > & getInputInfos() const
Definition Job.h:245
Compilation - A set of tasks to perform for a single driver invocation.
Definition Compilation.h:46
static bool getDefaultModuleCachePath(SmallVectorImpl< char > &Result)
Compute the default -fmodule-cache-path.
Definition Clang.cpp:4045
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:284
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:329
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
Top level wrappers for InstallAPI frontend operations.
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...
const FunctionProtoType * T
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.
std::string LogPath
The path to a log file, which logs timing of actions performed by the dependency scanner.
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:86
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)