From 8752920875f29a10ccebc3dedc271e17cb6cbb06 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Sun, 30 Jun 2024 15:56:39 -0400 Subject: [PATCH] Allow module aliases to be expressed in the explicit Swift module map JSON file. For build systems that already generate these files, it makes sense to include the aliases so that the map file serves as a comprehensive index of how the module inputs are referenced. --- include/swift/AST/ASTContext.h | 4 ++ .../swift/Frontend/ModuleInterfaceLoader.h | 28 +++++--- lib/AST/ASTContext.cpp | 16 +++-- lib/Frontend/ModuleInterfaceLoader.cpp | 17 ++++- lib/Serialization/ScanningLoaders.cpp | 3 +- ...e-alias-explicit-build-alias-in-json.swift | 66 +++++++++++++++++++ 6 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 test/Frontend/module-alias-explicit-build-alias-in-json.swift diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 1de3f77b2f1..844d1fea443 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -615,6 +615,10 @@ public: /// are the real (physical) module names on disk. void setModuleAliases(const llvm::StringMap &aliasMap); + /// Adds a given alias to the map of Identifiers between module aliases and + /// their actual names. + void addModuleAlias(StringRef moduleAlias, StringRef realName); + /// Look up option used in \c getRealModuleName when module aliasing is applied. enum class ModuleAliasLookupOption { alwaysRealName, diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index f05c6575644..5b599128958 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -318,10 +318,11 @@ class ExplicitModuleMapParser { public: ExplicitModuleMapParser(llvm::BumpPtrAllocator &Allocator) : Saver(Allocator) {} - std::error_code - parseSwiftExplicitModuleMap(llvm::MemoryBufferRef BufferRef, - llvm::StringMap &swiftModuleMap, - llvm::StringMap &clangModuleMap) { + std::error_code parseSwiftExplicitModuleMap( + llvm::MemoryBufferRef BufferRef, + llvm::StringMap &swiftModuleMap, + llvm::StringMap &clangModuleMap, + llvm::StringMap &moduleAliases) { using namespace llvm::yaml; // Use a new source manager instead of the one from ASTContext because we // don't want the JSON file to be persistent. @@ -331,7 +332,8 @@ public: assert(DI != Stream.end() && "Failed to read a document"); if (auto *MN = dyn_cast_or_null(DI->getRoot())) { for (auto &entry : *MN) { - if (parseSingleModuleEntry(entry, swiftModuleMap, clangModuleMap)) { + if (parseSingleModuleEntry(entry, swiftModuleMap, clangModuleMap, + moduleAliases)) { return std::make_error_code(std::errc::invalid_argument); } } @@ -359,16 +361,19 @@ private: llvm_unreachable("Unexpected JSON value for isFramework"); } - bool parseSingleModuleEntry(llvm::yaml::Node &node, - llvm::StringMap &swiftModuleMap, - llvm::StringMap &clangModuleMap) { + bool parseSingleModuleEntry( + llvm::yaml::Node &node, + llvm::StringMap &swiftModuleMap, + llvm::StringMap &clangModuleMap, + llvm::StringMap &moduleAliases) { using namespace llvm::yaml; auto *mapNode = dyn_cast(&node); if (!mapNode) return true; StringRef moduleName; std::optional swiftModulePath, swiftModuleDocPath, - swiftModuleSourceInfoPath, swiftModuleCacheKey, clangModuleCacheKey; + swiftModuleSourceInfoPath, swiftModuleCacheKey, clangModuleCacheKey, + moduleAlias; std::optional> headerDependencyPaths; std::string clangModuleMapPath = "", clangModulePath = ""; bool isFramework = false, isSystem = false, @@ -405,6 +410,8 @@ private: clangModuleCacheKey = val.str(); } else if (key == "isBridgingHeaderDependency") { isBridgingHeaderDependency = parseBoolValue(val); + } else if (key == "moduleAlias") { + moduleAlias = val.str(); } else { // Being forgiving for future fields. continue; @@ -439,6 +446,9 @@ private: clangModuleCacheKey); didInsert = clangModuleMap.try_emplace(moduleName, std::move(entry)).second; } + if (didInsert && moduleAlias.has_value()) { + moduleAliases[*moduleAlias] = moduleName; + } // Prevent duplicate module names. return !didInsert; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9c43e5f05ea..7f495105e92 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2136,16 +2136,20 @@ void ASTContext::setModuleAliases(const llvm::StringMap &aliasMap) { for (auto k: aliasMap.keys()) { auto v = aliasMap.lookup(k); if (!v.empty()) { - auto key = getIdentifier(k); - auto val = getIdentifier(v); - // key is a module alias, val is its corresponding real name - ModuleAliasMap[key] = std::make_pair(val, true); - // add an entry with an alias as key for an easier lookup later - ModuleAliasMap[val] = std::make_pair(key, false); + addModuleAlias(k, v); } } } +void ASTContext::addModuleAlias(StringRef moduleAlias, StringRef realName) { + auto key = getIdentifier(moduleAlias); + auto val = getIdentifier(realName); + // key is a module alias, val is its corresponding real name + ModuleAliasMap[key] = std::make_pair(val, true); + // add an entry with an alias as key for an easier lookup later + ModuleAliasMap[val] = std::make_pair(key, false); +} + Identifier ASTContext::getRealModuleName(Identifier key, ModuleAliasLookupOption option) const { auto found = ModuleAliasMap.find(key); if (found == ModuleAliasMap.end()) diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 66de99bf711..81572470d07 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -2183,6 +2183,14 @@ InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName, return action(info); } +static void addModuleAliasesFromExplicitSwiftModuleMap( + ASTContext &Ctx, llvm::StringMap ModuleAliases) { + for (auto &entry : ModuleAliases) { + Ctx.addModuleAlias(/*moduleAlias=*/entry.getKey(), + /*realModule=*/entry.getValue()); + } +} + struct ExplicitSwiftModuleLoader::Implementation { ASTContext &Ctx; llvm::BumpPtrAllocator Allocator; @@ -2192,6 +2200,7 @@ struct ExplicitSwiftModuleLoader::Implementation { void parseSwiftExplicitModuleMap(StringRef fileName) { ExplicitModuleMapParser parser(Allocator); llvm::StringMap ExplicitClangModuleMap; + llvm::StringMap ModuleAliases; // Load the input file. llvm::ErrorOr> fileBufOrErr = llvm::MemoryBuffer::getFile(fileName); @@ -2203,7 +2212,7 @@ struct ExplicitSwiftModuleLoader::Implementation { auto hasError = parser.parseSwiftExplicitModuleMap( (*fileBufOrErr)->getMemBufferRef(), ExplicitModuleMap, - ExplicitClangModuleMap); + ExplicitClangModuleMap, ModuleAliases); if (hasError) Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_corrupted, @@ -2230,6 +2239,7 @@ struct ExplicitSwiftModuleLoader::Implementation { .str()); } } + addModuleAliasesFromExplicitSwiftModuleMap(Ctx, ModuleAliases); } void addCommandLineExplicitInputs( @@ -2462,6 +2472,7 @@ struct ExplicitCASModuleLoader::Implementation { void parseSwiftExplicitModuleMap(StringRef ID) { ExplicitModuleMapParser parser(Allocator); llvm::StringMap ExplicitClangModuleMap; + llvm::StringMap ModuleAliases; auto buf = loadBuffer(ID); if (!buf) { Ctx.Diags.diagnose(SourceLoc(), diag::error_cas, @@ -2477,7 +2488,8 @@ struct ExplicitCASModuleLoader::Implementation { llvm::MemoryBuffer::getFile(ID); auto hasError = parser.parseSwiftExplicitModuleMap( - (*buf)->getMemBufferRef(), ExplicitModuleMap, ExplicitClangModuleMap); + (*buf)->getMemBufferRef(), ExplicitModuleMap, ExplicitClangModuleMap, + ModuleAliases); if (hasError) Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_corrupted, @@ -2516,6 +2528,7 @@ struct ExplicitCASModuleLoader::Implementation { extraClangArgs.push_back(*cachePath); } } + addModuleAliasesFromExplicitSwiftModuleMap(Ctx, ModuleAliases); } void addCommandLineExplicitInputs( diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index 4b27683652e..0dbcad4df48 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -112,6 +112,7 @@ void PlaceholderSwiftModuleScanner::parsePlaceholderModuleMap( StringRef fileName) { ExplicitModuleMapParser parser(Allocator); llvm::StringMap ClangDependencyModuleMap; + llvm::StringMap ModuleAliases; llvm::ErrorOr> fileBufOrErr = llvm::MemoryBuffer::getFile(fileName); if (!fileBufOrErr) { @@ -121,7 +122,7 @@ void PlaceholderSwiftModuleScanner::parsePlaceholderModuleMap( } auto result = parser.parseSwiftExplicitModuleMap( (*fileBufOrErr)->getMemBufferRef(), PlaceholderDependencyModuleMap, - ClangDependencyModuleMap); + ClangDependencyModuleMap, ModuleAliases); if (result == std::errc::invalid_argument) { Ctx.Diags.diagnose(SourceLoc(), diag::placeholder_dependency_module_map_corrupted, diff --git a/test/Frontend/module-alias-explicit-build-alias-in-json.swift b/test/Frontend/module-alias-explicit-build-alias-in-json.swift new file mode 100644 index 00000000000..c2919db2361 --- /dev/null +++ b/test/Frontend/module-alias-explicit-build-alias-in-json.swift @@ -0,0 +1,66 @@ +/// Test setting a module alias in the explicit module loader's JSON directly. +// UNSUPPORTED: OS=windows-msvc +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/inputs +// RUN: mkdir -p %t/outputs + +/// Create a module Bar +// RUN: echo 'public func bar() {}' > %t/inputs/FileBar.swift +// RUN: %target-swift-frontend -module-name Bar %t/inputs/FileBar.swift -emit-module -emit-module-path %t/inputs/Bar.swiftmodule +// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/SwiftShims.pcm +// RUN: %target-swift-emit-pcm -module-name _SwiftConcurrencyShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/_SwiftConcurrencyShims.pcm + +/// Check Bar.swiftmodule is created +// RUN: test -f %t/inputs/Bar.swiftmodule + +/// Next create an explicit module dependency map to build module Foo +// RUN: echo 'import Cat' > %t/inputs/FileFoo.swift + +// RUN: echo "[{" > %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Bar\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/t/inputs/Bar.swiftmodule\"," >> %/t/inputs/map.json +// RUN: echo "\"moduleAlias\": \"Cat\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/concurrency_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"SwiftShims\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json +// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %/t/inputs/map.json +// RUN: echo "\"clangModulePath\": \"%t/inputs/SwiftShims.pcm\"" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"_SwiftConcurrencyShims\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json +// RUN: echo "\"clangModuleMapPath\": \"%swift-lib-dir/swift/shims/module.modulemap\"," >> %/t/inputs/map.json +// RUN: echo "\"clangModulePath\": \"%t/inputs/_SwiftConcurrencyShims.pcm\"" >> %/t/inputs/map.json +// RUN: echo "}," >> %/t/inputs/map.json +// RUN: echo "{" >> %/t/inputs/map.json +// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/inputs/map.json +// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %/t/inputs/map.json +// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json +// RUN: echo "}]" >> %/t/inputs/map.json + +/// Create a module Foo that imports Cat aliased to Bar in the JSON above +// RUN: %target-swift-frontend -module-name Foo %t/inputs/FileFoo.swift -I %t/inputs -emit-module -emit-module-path %t/outputs/Foo.swiftmodule -disable-implicit-swift-modules -explicit-swift-module-map-file %t/inputs/map.json -Rmodule-loading 2> %t/outputs/load-result.output + +// RUN: test -f %t/outputs/Foo.swiftmodule +// RUN: test -f %t/inputs/Bar.swiftmodule +// RUN: not test -f %t/inputs/Cat.swiftmodule + +// RUN: %FileCheck %s -input-file %t/outputs/load-result.output -check-prefix CHECK +// CHECK: remark: loaded module {{.*}}Bar.swiftmodule