Skip to content

ModuleInterface: teach module build action to use fall-back interface if building canonical interface failed #37489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions include/swift/AST/ModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ class ModuleInterfaceChecker {
ArrayRef<std::string> candidates,
StringRef outPath) = 0;
virtual ~ModuleInterfaceChecker() = default;
virtual std::string getBackupPublicModuleInterfacePath(StringRef moduleName,
StringRef interfacePath) = 0;
};

/// Abstract interface to run an action in a sub ASTContext.
Expand Down
2 changes: 0 additions & 2 deletions include/swift/Frontend/ModuleInterfaceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,6 @@ class ModuleInterfaceCheckerImpl: public ModuleInterfaceChecker {
ArrayRef<std::string> candidates,
StringRef outPath) override;
bool isCached(StringRef DepPath);
std::string getBackupPublicModuleInterfacePath(StringRef moduleName,
StringRef interfacePath) override;
};

/// A ModuleLoader that runs a subordinate \c CompilerInvocation and
Expand Down
51 changes: 32 additions & 19 deletions lib/Frontend/ModuleInterfaceLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,17 @@ class ModuleInterfaceLoaderImpl {
}

std::string getBackupPublicModuleInterfacePath() {
return getBackupPublicModuleInterfacePath(ctx.SourceMgr, backupInterfaceDir,
moduleName, interfacePath);
}

static std::string getBackupPublicModuleInterfacePath(SourceManager &SM,
StringRef backupInterfaceDir,
StringRef moduleName,
StringRef interfacePath) {
if (backupInterfaceDir.empty())
return std::string();
auto &fs = *ctx.SourceMgr.getFileSystem();
auto &fs = *SM.getFileSystem();
auto fileName = llvm::sys::path::filename(interfacePath);
{
llvm::SmallString<256> path(backupInterfaceDir);
Expand Down Expand Up @@ -1145,21 +1153,6 @@ ModuleInterfaceCheckerImpl::getCompiledModuleCandidatesForInterface(
return results;
}

std::string
ModuleInterfaceCheckerImpl::getBackupPublicModuleInterfacePath(StringRef moduleName,
StringRef interfacePath) {
// Derive .swiftmodule path from the .swiftinterface path.
auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile);
llvm::SmallString<32> modulePath = interfacePath;
llvm::sys::path::replace_extension(modulePath, newExt);
ModuleInterfaceLoaderImpl Impl(Ctx, modulePath, interfacePath, moduleName,
CacheDir, PrebuiltCacheDir, BackupInterfaceDir,
SourceLoc(), Opts,
RequiresOSSAModules, nullptr,
ModuleLoadingMode::PreferSerialized);
return Impl.getBackupPublicModuleInterfacePath();
}

bool ModuleInterfaceCheckerImpl::tryEmitForwardingModule(
StringRef moduleName, StringRef interfacePath,
ArrayRef<std::string> candidates, StringRef outputPath) {
Expand Down Expand Up @@ -1212,9 +1205,29 @@ bool ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface(
LoaderOpts.disableInterfaceLock);
// FIXME: We really only want to serialize 'important' dependencies here, if
// we want to ship the built swiftmodules to another machine.
return builder.buildSwiftModule(OutPath, /*shouldSerializeDeps*/true,
/*ModuleBuffer*/nullptr, nullptr,
SearchPathOpts.CandidateCompiledModules);
auto failed = builder.buildSwiftModule(OutPath, /*shouldSerializeDeps*/true,
/*ModuleBuffer*/nullptr, nullptr,
SearchPathOpts.CandidateCompiledModules);
if (!failed)
return false;
auto backInPath =
ModuleInterfaceLoaderImpl::getBackupPublicModuleInterfacePath(SourceMgr,
BackupInterfaceDir, ModuleName, InPath);
if (backInPath.empty())
return true;
assert(failed);
assert(!backInPath.empty());
ModuleInterfaceBuilder backupBuilder(SourceMgr, &Diags, astDelegate, backInPath,
ModuleName, CacheDir, PrebuiltCacheDir,
BackupInterfaceDir,
LoaderOpts.disableInterfaceLock);
// Ensure we can rebuild module after user changed the original interface file.
backupBuilder.addExtraDependency(InPath);
// FIXME: We really only want to serialize 'important' dependencies here, if
// we want to ship the built swiftmodules to another machine.
return backupBuilder.buildSwiftModule(OutPath, /*shouldSerializeDeps*/true,
/*ModuleBuffer*/nullptr, nullptr,
SearchPathOpts.CandidateCompiledModules);
}

void ModuleInterfaceLoader::collectVisibleTopLevelModuleNames(
Expand Down
14 changes: 14 additions & 0 deletions test/ModuleInterface/build-alternative-interface-explicit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/sources)
// RUN: %empty-directory(%t/inputs)
// RUN: %empty-directory(%t/alternative-inputs)
// RUN: %empty-directory(%t/module-cache)
// RUN: %empty-directory(%t/outputs)

// RUN: echo "public func foo() {}" > %t/sources/Foo.swift
// RUN: %target-swift-frontend-typecheck -emit-module-interface-path %t/inputs/Foo.swiftinterface %t/sources/Foo.swift -module-name Foo -disable-implicit-concurrency-module-import -enable-library-evolution -module-cache-path %t/module-cache -I %t/inputs -swift-version 5
// RUN: cp %t/inputs/Foo.swiftinterface %t/alternative-inputs/Foo.swiftinterface
// RUN: echo "mess_mess_mess" >> %t/inputs/Foo.swiftinterface
// RUN: not %target-swift-frontend -compile-module-from-interface -module-name Foo %t/inputs/Foo.swiftinterface -o %t/outputs/Foo.swiftmodule

// RUN: %target-swift-frontend -compile-module-from-interface -module-name Foo %t/inputs/Foo.swiftinterface -o %t/outputs/Foo.swiftmodule -backup-module-interface-path %t/alternative-inputs