mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Allow Clang modules to be listed in the explicit module map.
This lets users of `-explicit-swift-module-map-file` use a single mapping for all module dependencies, regardless of whether they're Swift or Clang modules, instead of manually splitting them among this file and command line flags.
This commit is contained in:
@@ -173,19 +173,24 @@ public:
|
||||
~ExplicitSwiftModuleLoader();
|
||||
};
|
||||
|
||||
/// Information about explicitly specified Swift module files.
|
||||
/// Information about explicitly specified Swift and Clang module files.
|
||||
struct ExplicitModuleInfo {
|
||||
// Path of the .swiftmodule file.
|
||||
// Path of the .swiftmodule file. Empty for pure Clang modules.
|
||||
std::string modulePath;
|
||||
// Path of the .swiftmoduledoc file.
|
||||
// Path of the .swiftmoduledoc file. Empty for pure Clang modules.
|
||||
std::string moduleDocPath;
|
||||
// Path of the .swiftsourceinfo file.
|
||||
// Path of the .swiftsourceinfo file. Empty for pure Clang modules.
|
||||
std::string moduleSourceInfoPath;
|
||||
// A flag that indicates whether this module is a framework
|
||||
bool isFramework = false;
|
||||
// A flag that indicates whether this module is a system module
|
||||
// Set the default to be false.
|
||||
bool isSystem = false;
|
||||
// Path of the Clang module map file. Empty for pure Swift modules.
|
||||
std::string clangModuleMapPath;
|
||||
// Path of a compiled Clang explicit module file. Empty for pure Swift
|
||||
// modules.
|
||||
std::string clangModulePath;
|
||||
};
|
||||
|
||||
/// Parser of explicit module maps passed into the compiler.
|
||||
@@ -194,15 +199,19 @@ struct ExplicitModuleInfo {
|
||||
// "moduleName": "A",
|
||||
// "modulePath": "A.swiftmodule",
|
||||
// "docPath": "A.swiftdoc",
|
||||
// "sourceInfoPath": "A.swiftsourceinfo"
|
||||
// "isFramework": false
|
||||
// "sourceInfoPath": "A.swiftsourceinfo",
|
||||
// "isFramework": false,
|
||||
// "clangModuleMapPath": "A/module.modulemap",
|
||||
// "clangModulePath": "A.pcm",
|
||||
// },
|
||||
// {
|
||||
// "moduleName": "B",
|
||||
// "modulePath": "B.swiftmodule",
|
||||
// "docPath": "B.swiftdoc",
|
||||
// "sourceInfoPath": "B.swiftsourceinfo"
|
||||
// "isFramework": false
|
||||
// "sourceInfoPath": "B.swiftsourceinfo",
|
||||
// "isFramework": false,
|
||||
// "clangModuleMapPath": "B/module.modulemap",
|
||||
// "clangModulePath": "B.pcm",
|
||||
// }
|
||||
// ]
|
||||
class ExplicitModuleMapParser {
|
||||
@@ -279,6 +288,10 @@ private:
|
||||
result.isFramework = parseBoolValue(val);
|
||||
} else if (key == "isSystem") {
|
||||
result.isSystem = parseBoolValue(val);
|
||||
} else if (key == "clangModuleMapPath") {
|
||||
result.clangModuleMapPath = val.str();
|
||||
} else if (key == "clangModulePath") {
|
||||
result.clangModulePath = val.str();
|
||||
} else {
|
||||
// Being forgiving for future fields.
|
||||
continue;
|
||||
|
||||
@@ -554,6 +554,20 @@ bool CompilerInstance::setUpModuleLoaders() {
|
||||
Context->addModuleLoader(std::move(MemoryBufferLoader));
|
||||
}
|
||||
|
||||
// If using `-explicit-swift-module-map-file`, create the explicit loader
|
||||
// before creating `ClangImporter` because the entries in the map influence
|
||||
// the Clang flags. The loader is added to the context below.
|
||||
std::unique_ptr<ExplicitSwiftModuleLoader> ESML = nullptr;
|
||||
bool ExplicitModuleBuild =
|
||||
Invocation.getFrontendOptions().DisableImplicitModules;
|
||||
if (ExplicitModuleBuild ||
|
||||
!Invocation.getSearchPathOptions().ExplicitSwiftModuleMap.empty()) {
|
||||
ESML = ExplicitSwiftModuleLoader::create(
|
||||
*Context, getDependencyTracker(), MLM,
|
||||
Invocation.getSearchPathOptions().ExplicitSwiftModuleMap,
|
||||
IgnoreSourceInfoFile);
|
||||
}
|
||||
|
||||
// Wire up the Clang importer. If the user has specified an SDK, use it.
|
||||
// Otherwise, we just keep it around as our interface to Clang's ABI
|
||||
// knowledge.
|
||||
@@ -575,15 +589,9 @@ bool CompilerInstance::setUpModuleLoaders() {
|
||||
*Context, ModuleCachePath, FEOpts.PrebuiltModuleCachePath,
|
||||
FEOpts.BackupModuleInterfaceDir, LoaderOpts,
|
||||
RequireOSSAModules_t(Invocation.getSILOptions())));
|
||||
// If implicit modules are disabled, we need to install an explicit module
|
||||
// loader.
|
||||
bool ExplicitModuleBuild = Invocation.getFrontendOptions().DisableImplicitModules;
|
||||
if (ExplicitModuleBuild || !Invocation.getSearchPathOptions().ExplicitSwiftModuleMap.empty()) {
|
||||
auto ESML = ExplicitSwiftModuleLoader::create(
|
||||
*Context,
|
||||
getDependencyTracker(), MLM,
|
||||
Invocation.getSearchPathOptions().ExplicitSwiftModuleMap,
|
||||
IgnoreSourceInfoFile);
|
||||
|
||||
// Install an explicit module loader if it was created earlier.
|
||||
if (ESML) {
|
||||
this->DefaultSerializedLoader = ESML.get();
|
||||
Context->addModuleLoader(std::move(ESML));
|
||||
}
|
||||
|
||||
@@ -1875,6 +1875,27 @@ struct ExplicitSwiftModuleLoader::Implementation {
|
||||
else if (result == std::errc::no_such_file_or_directory)
|
||||
Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_missing,
|
||||
fileName);
|
||||
|
||||
// A single module map can define multiple modules; keep track of the ones
|
||||
// we've seen so that we don't generate duplicate flags.
|
||||
std::set<std::string> moduleMapsSeen;
|
||||
std::vector<std::string> &extraClangArgs = Ctx.ClangImporterOpts.ExtraArgs;
|
||||
for (auto &entry : ExplicitModuleMap) {
|
||||
const auto &moduleMapPath = entry.getValue().clangModuleMapPath;
|
||||
if (!moduleMapPath.empty() &&
|
||||
moduleMapsSeen.find(moduleMapPath) == moduleMapsSeen.end()) {
|
||||
moduleMapsSeen.insert(moduleMapPath);
|
||||
extraClangArgs.push_back(
|
||||
(Twine("-fmodule-map-file=") + moduleMapPath).str());
|
||||
}
|
||||
|
||||
const auto &modulePath = entry.getValue().clangModulePath;
|
||||
if (!modulePath.empty()) {
|
||||
extraClangArgs.push_back(
|
||||
(Twine("-fmodule-file=") + entry.getKey() + "=" + modulePath)
|
||||
.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1910,6 +1931,16 @@ bool ExplicitSwiftModuleLoader::findModule(ImportPath::Element ModuleID,
|
||||
}
|
||||
auto &moduleInfo = it->getValue();
|
||||
|
||||
// If this is only a Clang module with no paired Swift module, return false
|
||||
// now so that we don't emit diagnostics about it being missing. This gives
|
||||
// ClangImporter an opportunity to import it.
|
||||
bool hasClangModule = !moduleInfo.clangModuleMapPath.empty() ||
|
||||
!moduleInfo.clangModulePath.empty();
|
||||
bool hasSwiftModule = !moduleInfo.modulePath.empty();
|
||||
if (hasClangModule && !hasSwiftModule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set IsFramework bit according to the moduleInfo
|
||||
IsFramework = moduleInfo.isFramework;
|
||||
IsSystemModule = moduleInfo.isSystem;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: mkdir -p %t/clang-module-cache
|
||||
// RUN: mkdir -p %t/inputs
|
||||
// RUN: echo "public func anotherFuncA() {}" > %t/A.swift
|
||||
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/inputs/A.swiftmodule -emit-module-doc-path %t/inputs/A.swiftdoc -emit-module-source-info -emit-module-source-info-path %t/inputs/A.swiftsourceinfo -import-underlying-module -I%S/Inputs/CHeaders -module-cache-path %t.module-cache %t/A.swift -module-name A
|
||||
|
||||
// RUN: echo "[{" > %/t/inputs/map.json
|
||||
// RUN: echo "\"moduleName\": \"A\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"modulePath\": \"%/t/inputs/A.swiftmodule\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"docPath\": \"%/t/inputs/A.swiftdoc\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/A.swiftsourceinfo\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"clangModuleMapPath\": \"%/S/Inputs/CHeaders/module.modulemap\"" >> %/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\": \"_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
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/Foo.swiftmodule -module-cache-path %t.module-cache -explicit-swift-module-map-file %t/inputs/map.json %s
|
||||
|
||||
import A
|
||||
|
||||
func callA() {
|
||||
funcA()
|
||||
anotherFuncA()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: mkdir -p %t/clang-module-cache
|
||||
// RUN: mkdir -p %t/inputs
|
||||
|
||||
// RUN: echo "[{" > %/t/inputs/map.json
|
||||
// RUN: echo "\"moduleName\": \"A\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"clangModuleMapPath\": \"%/S/Inputs/CHeaders/module.modulemap\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"clangModulePath\": \"%t/inputs/A.pcm\"" >> %/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\": \"_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
|
||||
|
||||
// RUN: %target-swift-emit-pcm -module-name A -o %t/inputs/A.pcm %S/Inputs/CHeaders/module.modulemap
|
||||
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/Foo.swiftmodule -module-cache-path %t.module-cache -explicit-swift-module-map-file %t/inputs/map.json %s
|
||||
|
||||
import A
|
||||
|
||||
func callA() {
|
||||
funcA()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: mkdir -p %t/clang-module-cache
|
||||
// RUN: mkdir -p %t/inputs
|
||||
|
||||
// RUN: echo "[{" > %/t/inputs/map.json
|
||||
// RUN: echo "\"moduleName\": \"A\"," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
|
||||
// RUN: echo "\"clangModuleMapPath\": \"%/S/Inputs/CHeaders/module.modulemap\"" >> %/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\": \"_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
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/Foo.swiftmodule -module-cache-path %t.module-cache -explicit-swift-module-map-file %t/inputs/map.json %s
|
||||
|
||||
import A
|
||||
|
||||
func callA() {
|
||||
funcA()
|
||||
}
|
||||
Reference in New Issue
Block a user