Skip to content

Commit b6cd513

Browse files
committed
Frontend: teach the compiler to use a backup directory to find .swiftinterface files to compile
This mechanism allows the compiler to use a backup interface file to build into a binary module when a corresponding interface file from the SDK is failing for whatever reasons. This mechansim should be entirely opaque to end users except several diagnostic messages communicating backup interfaces are used. Part of rdar://77676064
1 parent 7487c12 commit b6cd513

20 files changed

+304
-75
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ ERROR(error_option_required,none, "option '%0' is required", (StringRef))
405405
ERROR(error_nonexistent_output_dir,none,
406406
"'-output-dir' argument '%0' does not exist or is not a directory", (StringRef))
407407

408+
REMARK(interface_file_backup_used,none,
409+
"building module from '%0' failed; retrying building module from '%1'", (StringRef, StringRef))
408410

409411
// Dependency Verifier Diagnostics
410412
ERROR(missing_member_dependency,none,

include/swift/AST/ModuleLoader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ class ModuleInterfaceChecker {
157157
ArrayRef<std::string> candidates,
158158
StringRef outPath) = 0;
159159
virtual ~ModuleInterfaceChecker() = default;
160+
virtual std::string getBackupPublicModuleInterfacePath(StringRef moduleName,
161+
StringRef interfacePath) = 0;
160162
};
161163

162164
/// Abstract interface to run an action in a sub ASTContext.

include/swift/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ class FrontendOptions {
8181
/// binary module has already been built for use by the compiler.
8282
std::string PrebuiltModuleCachePath;
8383

84+
/// The path to look in to find backup .swiftinterface files if those found
85+
/// from SDKs are failing.
86+
std::string BackupModuleInterfaceDir;
87+
8488
/// For these modules, we should prefer using Swift interface when importing them.
8589
std::vector<std::string> PreferInterfaceForModules;
8690

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,25 @@ class ModuleInterfaceCheckerImpl: public ModuleInterfaceChecker {
336336
ASTContext &Ctx;
337337
std::string CacheDir;
338338
std::string PrebuiltCacheDir;
339+
std::string BackupInterfaceDir;
339340
ModuleInterfaceLoaderOptions Opts;
340341
RequireOSSAModules_t RequiresOSSAModules;
341342

342343
public:
343344
explicit ModuleInterfaceCheckerImpl(ASTContext &Ctx, StringRef cacheDir,
344345
StringRef prebuiltCacheDir,
346+
StringRef BackupInterfaceDir,
345347
ModuleInterfaceLoaderOptions opts,
346348
RequireOSSAModules_t requiresOSSAModules)
347349
: Ctx(Ctx), CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir),
350+
BackupInterfaceDir(BackupInterfaceDir),
348351
Opts(opts), RequiresOSSAModules(requiresOSSAModules) {}
349-
352+
explicit ModuleInterfaceCheckerImpl(ASTContext &Ctx, StringRef cacheDir,
353+
StringRef prebuiltCacheDir,
354+
ModuleInterfaceLoaderOptions opts,
355+
RequireOSSAModules_t requiresOSSAModules):
356+
ModuleInterfaceCheckerImpl(Ctx, cacheDir, prebuiltCacheDir, StringRef(),
357+
opts, requiresOSSAModules) {}
350358
std::vector<std::string>
351359
getCompiledModuleCandidatesForInterface(StringRef moduleName,
352360
StringRef interfacePath) override;
@@ -359,6 +367,8 @@ class ModuleInterfaceCheckerImpl: public ModuleInterfaceChecker {
359367
ArrayRef<std::string> candidates,
360368
StringRef outPath) override;
361369
bool isCached(StringRef DepPath);
370+
std::string getBackupPublicModuleInterfacePath(StringRef moduleName,
371+
StringRef interfacePath) override;
362372
};
363373

364374
/// A ModuleLoader that runs a subordinate \c CompilerInvocation and
@@ -414,7 +424,8 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
414424
SourceManager &SourceMgr, DiagnosticEngine &Diags,
415425
const SearchPathOptions &SearchPathOpts, const LangOptions &LangOpts,
416426
const ClangImporterOptions &ClangOpts, StringRef CacheDir,
417-
StringRef PrebuiltCacheDir, StringRef ModuleName, StringRef InPath,
427+
StringRef PrebuiltCacheDir, StringRef BackupInterfaceDir,
428+
StringRef ModuleName, StringRef InPath,
418429
StringRef OutPath, bool SerializeDependencyHashes,
419430
bool TrackSystemDependencies, ModuleInterfaceLoaderOptions Opts,
420431
RequireOSSAModules_t RequireOSSAModules);
@@ -423,7 +434,9 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
423434
struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
424435
private:
425436
SourceManager &SM;
426-
DiagnosticEngine &Diags;
437+
public:
438+
DiagnosticEngine *Diags;
439+
private:
427440
llvm::BumpPtrAllocator Allocator;
428441
llvm::StringSaver ArgSaver;
429442
std::vector<StringRef> GenericArgs;
@@ -439,7 +452,7 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
439452
// Diagnose this inside the interface file, if possible.
440453
loc = SM.getLocFromExternalSource(interfacePath, 1, 1);
441454
}
442-
return Diags.diagnose(loc, ID, std::move(Args)...);
455+
return Diags->diagnose(loc, ID, std::move(Args)...);
443456
}
444457
void
445458
inheritOptionsForBuildingInterface(const SearchPathOptions &SearchPathOpts,
@@ -452,11 +465,12 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
452465
SourceLoc diagnosticLoc);
453466
public:
454467
InterfaceSubContextDelegateImpl(
455-
SourceManager &SM, DiagnosticEngine &Diags,
468+
SourceManager &SM, DiagnosticEngine *Diags,
456469
const SearchPathOptions &searchPathOpts, const LangOptions &langOpts,
457470
const ClangImporterOptions &clangImporterOpts,
458471
ModuleInterfaceLoaderOptions LoaderOpts, bool buildModuleCacheDirIfAbsent,
459472
StringRef moduleCachePath, StringRef prebuiltCachePath,
473+
StringRef backupModuleInterfaceDir,
460474
bool serializeDependencyHashes, bool trackSystemDependencies,
461475
RequireOSSAModules_t requireOSSAModules);
462476
std::error_code runInSubContext(StringRef moduleName,

include/swift/Option/FrontendOptions.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,13 @@ def prebuilt_module_cache_path_EQ :
695695
Joined<["-"], "prebuilt-module-cache-path=">,
696696
Alias<prebuilt_module_cache_path>;
697697

698+
def backup_module_interface_path :
699+
Separate<["-"], "backup-module-interface-path">,
700+
HelpText<"Directory of module interfaces as backups to those from SDKs">;
701+
def backup_module_interface_path_EQ :
702+
Joined<["-"], "backup-module-interface-path=">,
703+
Alias<backup_module_interface_path>;
704+
698705
def force_public_linkage : Flag<["-"], "force-public-linkage">,
699706
HelpText<"Force public linkage for private symbols. Used by LLDB.">;
700707

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ class SerializedASTFile final : public LoadedFile {
471471
/// Extract compiler arguments from an interface file buffer.
472472
bool extractCompilerFlagsFromInterface(StringRef buffer, llvm::StringSaver &ArgSaver,
473473
SmallVectorImpl<const char *> &SubArgs);
474+
475+
/// Extract the user module version number from an interface file.
476+
llvm::VersionTuple extractUserModuleVersionFromInterface(StringRef moduleInterfacePath);
474477
} // end namespace swift
475478

476479
#endif

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,10 +1240,11 @@ swift::dependencies::performModuleScan(CompilerInstance &instance,
12401240
auto &FEOpts = instance.getInvocation().getFrontendOptions();
12411241
ModuleInterfaceLoaderOptions LoaderOpts(FEOpts);
12421242
InterfaceSubContextDelegateImpl ASTDelegate(
1243-
ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts,
1243+
ctx.SourceMgr, &ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts,
12441244
ctx.ClangImporterOpts, LoaderOpts,
12451245
/*buildModuleCacheDirIfAbsent*/ false, ModuleCachePath,
12461246
FEOpts.PrebuiltModuleCachePath,
1247+
FEOpts.BackupModuleInterfaceDir,
12471248
FEOpts.SerializeModuleInterfaceDependencyHashes,
12481249
FEOpts.shouldTrackSystemDependencies(),
12491250
RequireOSSAModules_t(instance.getSILOptions()));
@@ -1332,10 +1333,11 @@ swift::dependencies::performBatchModuleScan(
13321333
std::set<ModuleDependencyID>>
13331334
allModules;
13341335
InterfaceSubContextDelegateImpl ASTDelegate(
1335-
ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts,
1336+
ctx.SourceMgr, &ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts,
13361337
ctx.ClangImporterOpts, LoaderOpts,
13371338
/*buildModuleCacheDirIfAbsent*/ false, ModuleCachePath,
13381339
FEOpts.PrebuiltModuleCachePath,
1340+
FEOpts.BackupModuleInterfaceDir,
13391341
FEOpts.SerializeModuleInterfaceDependencyHashes,
13401342
FEOpts.shouldTrackSystemDependencies(),
13411343
RequireOSSAModules_t(instance.getSILOptions()));
@@ -1400,10 +1402,11 @@ swift::dependencies::performBatchModulePrescan(
14001402
std::set<ModuleDependencyID>>
14011403
allModules;
14021404
InterfaceSubContextDelegateImpl ASTDelegate(
1403-
ctx.SourceMgr, ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts,
1405+
ctx.SourceMgr, &ctx.Diags, ctx.SearchPathOpts, ctx.LangOpts,
14041406
ctx.ClangImporterOpts, LoaderOpts,
14051407
/*buildModuleCacheDirIfAbsent*/ false, ModuleCachePath,
14061408
FEOpts.PrebuiltModuleCachePath,
1409+
FEOpts.BackupModuleInterfaceDir,
14071410
FEOpts.SerializeModuleInterfaceDependencyHashes,
14081411
FEOpts.shouldTrackSystemDependencies(),
14091412
RequireOSSAModules_t(instance.getSILOptions()));

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ bool ArgsToFrontendOptionsConverter::convert(
6363
if (const Arg *A = Args.getLastArg(OPT_prebuilt_module_cache_path)) {
6464
Opts.PrebuiltModuleCachePath = A->getValue();
6565
}
66+
if (const Arg *A = Args.getLastArg(OPT_backup_module_interface_path)) {
67+
Opts.BackupModuleInterfaceDir = A->getValue();
68+
}
6669
if (const Arg *A = Args.getLastArg(OPT_bridging_header_directory_for_print)) {
6770
Opts.BridgingHeaderDirForPrint = A->getValue();
6871
}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ void CompilerInvocation::setDefaultPrebuiltCacheIfNecessary() {
129129

130130
FrontendOpts.PrebuiltModuleCachePath = computePrebuiltCachePath(
131131
SearchPathOpts.RuntimeResourcePath, LangOpts.Target, LangOpts.SDKVersion);
132+
if (!FrontendOpts.PrebuiltModuleCachePath.empty())
133+
return;
134+
StringRef anchor = "prebuilt-modules";
135+
assert(((StringRef)FrontendOpts.PrebuiltModuleCachePath).contains(anchor));
136+
auto pair = ((StringRef)FrontendOpts.PrebuiltModuleCachePath).split(anchor);
137+
FrontendOpts.BackupModuleInterfaceDir =
138+
(llvm::Twine(pair.first) + "preferred-interfaces" + pair.second).str();
132139
}
133140

134141
static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts,

lib/Frontend/Frontend.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,8 @@ bool CompilerInstance::setUpModuleLoaders() {
530530
ModuleInterfaceLoaderOptions LoaderOpts(FEOpts);
531531
Context->addModuleInterfaceChecker(
532532
std::make_unique<ModuleInterfaceCheckerImpl>(
533-
*Context, ModuleCachePath, FEOpts.PrebuiltModuleCachePath, LoaderOpts,
533+
*Context, ModuleCachePath, FEOpts.PrebuiltModuleCachePath,
534+
FEOpts.BackupModuleInterfaceDir, LoaderOpts,
534535
RequireOSSAModules_t(Invocation.getSILOptions())));
535536
// If implicit modules are disabled, we need to install an explicit module
536537
// loader.
@@ -571,10 +572,11 @@ bool CompilerInstance::setUpModuleLoaders() {
571572
auto &FEOpts = Invocation.getFrontendOptions();
572573
ModuleInterfaceLoaderOptions LoaderOpts(FEOpts);
573574
InterfaceSubContextDelegateImpl ASTDelegate(
574-
Context->SourceMgr, Context->Diags, Context->SearchPathOpts,
575+
Context->SourceMgr, &Context->Diags, Context->SearchPathOpts,
575576
Context->LangOpts, Context->ClangImporterOpts, LoaderOpts,
576577
/*buildModuleCacheDirIfAbsent*/ false, ModuleCachePath,
577578
FEOpts.PrebuiltModuleCachePath,
579+
FEOpts.BackupModuleInterfaceDir,
578580
FEOpts.SerializeModuleInterfaceDependencyHashes,
579581
FEOpts.shouldTrackSystemDependencies(),
580582
RequireOSSAModules_t(Invocation.getSILOptions()));

lib/Frontend/ModuleInterfaceBuilder.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,11 @@ bool ModuleInterfaceBuilder::collectDepsForSerialization(
103103
// dependency list -- don't serialize that.
104104
if (!prebuiltCachePath.empty() && DepName.startswith(prebuiltCachePath))
105105
continue;
106-
106+
// Don't serialize interface path if it's from the preferred interface dir.
107+
// This ensures the prebuilt module caches generated from these interfaces are
108+
// relocatable.
109+
if (!backupInterfaceDir.empty() && DepName.startswith(backupInterfaceDir))
110+
continue;
107111
if (dependencyTracker) {
108112
dependencyTracker->addDependency(DepName, /*isSystem*/IsSDKRelative);
109113
}

lib/Frontend/ModuleInterfaceBuilder.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ class DependencyTracker;
3535

3636
class ModuleInterfaceBuilder {
3737
SourceManager &sourceMgr;
38-
DiagnosticEngine &diags;
38+
DiagnosticEngine *diags;
3939
InterfaceSubContextDelegate &subASTDelegate;
4040
const StringRef interfacePath;
4141
const StringRef moduleName;
4242
const StringRef moduleCachePath;
4343
const StringRef prebuiltCachePath;
44+
const StringRef backupInterfaceDir;
4445
const bool disableInterfaceFileLock;
4546
const SourceLoc diagnosticLoc;
4647
DependencyTracker *const dependencyTracker;
@@ -50,7 +51,7 @@ class ModuleInterfaceBuilder {
5051
/// Emit a diagnostic tied to this declaration.
5152
template<typename ...ArgTypes>
5253
static InFlightDiagnostic diagnose(
53-
DiagnosticEngine &Diags,
54+
DiagnosticEngine *Diags,
5455
SourceManager &SM,
5556
StringRef InterfacePath,
5657
SourceLoc Loc,
@@ -60,7 +61,7 @@ class ModuleInterfaceBuilder {
6061
// Diagnose this inside the interface file, if possible.
6162
Loc = SM.getLocFromExternalSource(InterfacePath, 1, 1);
6263
}
63-
return Diags.diagnose(Loc, ID, std::move(Args)...);
64+
return Diags->diagnose(Loc, ID, std::move(Args)...);
6465
}
6566

6667
private:
@@ -88,11 +89,12 @@ class ModuleInterfaceBuilder {
8889
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
8990
ArrayRef<std::string> CandidateModules);
9091
public:
91-
ModuleInterfaceBuilder(SourceManager &sourceMgr, DiagnosticEngine &diags,
92+
ModuleInterfaceBuilder(SourceManager &sourceMgr, DiagnosticEngine *diags,
9293
InterfaceSubContextDelegate &subASTDelegate,
9394
StringRef interfacePath,
9495
StringRef moduleName,
9596
StringRef moduleCachePath,
97+
StringRef backupInterfaceDir,
9698
StringRef prebuiltCachePath,
9799
bool disableInterfaceFileLock = false,
98100
SourceLoc diagnosticLoc = SourceLoc(),
@@ -101,6 +103,7 @@ class ModuleInterfaceBuilder {
101103
subASTDelegate(subASTDelegate),
102104
interfacePath(interfacePath), moduleName(moduleName),
103105
moduleCachePath(moduleCachePath), prebuiltCachePath(prebuiltCachePath),
106+
backupInterfaceDir(backupInterfaceDir),
104107
disableInterfaceFileLock(disableInterfaceFileLock),
105108
diagnosticLoc(diagnosticLoc), dependencyTracker(tracker) {}
106109

0 commit comments

Comments
 (0)