Skip to content

Commit ba26a1f

Browse files
authored
Merge pull request swiftlang#63178 from allevato/clang-modules-in-explicit-map
Allow Clang modules to be listed in the explicit module map.
2 parents 5b55428 + dda1cda commit ba26a1f

File tree

6 files changed

+188
-17
lines changed

6 files changed

+188
-17
lines changed

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,24 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase {
173173
~ExplicitSwiftModuleLoader();
174174
};
175175

176-
/// Information about explicitly specified Swift module files.
176+
/// Information about explicitly specified Swift and Clang module files.
177177
struct ExplicitModuleInfo {
178-
// Path of the .swiftmodule file.
178+
// Path of the .swiftmodule file. Empty for pure Clang modules.
179179
std::string modulePath;
180-
// Path of the .swiftmoduledoc file.
180+
// Path of the .swiftmoduledoc file. Empty for pure Clang modules.
181181
std::string moduleDocPath;
182-
// Path of the .swiftsourceinfo file.
182+
// Path of the .swiftsourceinfo file. Empty for pure Clang modules.
183183
std::string moduleSourceInfoPath;
184184
// A flag that indicates whether this module is a framework
185185
bool isFramework = false;
186186
// A flag that indicates whether this module is a system module
187187
// Set the default to be false.
188188
bool isSystem = false;
189+
// Path of the Clang module map file. Empty for pure Swift modules.
190+
std::string clangModuleMapPath;
191+
// Path of a compiled Clang explicit module file. Empty for pure Swift
192+
// modules.
193+
std::string clangModulePath;
189194
};
190195

191196
/// Parser of explicit module maps passed into the compiler.
@@ -194,15 +199,19 @@ struct ExplicitModuleInfo {
194199
// "moduleName": "A",
195200
// "modulePath": "A.swiftmodule",
196201
// "docPath": "A.swiftdoc",
197-
// "sourceInfoPath": "A.swiftsourceinfo"
198-
// "isFramework": false
202+
// "sourceInfoPath": "A.swiftsourceinfo",
203+
// "isFramework": false,
204+
// "clangModuleMapPath": "A/module.modulemap",
205+
// "clangModulePath": "A.pcm",
199206
// },
200207
// {
201208
// "moduleName": "B",
202209
// "modulePath": "B.swiftmodule",
203210
// "docPath": "B.swiftdoc",
204-
// "sourceInfoPath": "B.swiftsourceinfo"
205-
// "isFramework": false
211+
// "sourceInfoPath": "B.swiftsourceinfo",
212+
// "isFramework": false,
213+
// "clangModuleMapPath": "B/module.modulemap",
214+
// "clangModulePath": "B.pcm",
206215
// }
207216
// ]
208217
class ExplicitModuleMapParser {
@@ -279,6 +288,10 @@ class ExplicitModuleMapParser {
279288
result.isFramework = parseBoolValue(val);
280289
} else if (key == "isSystem") {
281290
result.isSystem = parseBoolValue(val);
291+
} else if (key == "clangModuleMapPath") {
292+
result.clangModuleMapPath = val.str();
293+
} else if (key == "clangModulePath") {
294+
result.clangModulePath = val.str();
282295
} else {
283296
// Being forgiving for future fields.
284297
continue;

lib/Frontend/Frontend.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,20 @@ bool CompilerInstance::setUpModuleLoaders() {
554554
Context->addModuleLoader(std::move(MemoryBufferLoader));
555555
}
556556

557+
// If using `-explicit-swift-module-map-file`, create the explicit loader
558+
// before creating `ClangImporter` because the entries in the map influence
559+
// the Clang flags. The loader is added to the context below.
560+
std::unique_ptr<ExplicitSwiftModuleLoader> ESML = nullptr;
561+
bool ExplicitModuleBuild =
562+
Invocation.getFrontendOptions().DisableImplicitModules;
563+
if (ExplicitModuleBuild ||
564+
!Invocation.getSearchPathOptions().ExplicitSwiftModuleMap.empty()) {
565+
ESML = ExplicitSwiftModuleLoader::create(
566+
*Context, getDependencyTracker(), MLM,
567+
Invocation.getSearchPathOptions().ExplicitSwiftModuleMap,
568+
IgnoreSourceInfoFile);
569+
}
570+
557571
// Wire up the Clang importer. If the user has specified an SDK, use it.
558572
// Otherwise, we just keep it around as our interface to Clang's ABI
559573
// knowledge.
@@ -575,15 +589,9 @@ bool CompilerInstance::setUpModuleLoaders() {
575589
*Context, ModuleCachePath, FEOpts.PrebuiltModuleCachePath,
576590
FEOpts.BackupModuleInterfaceDir, LoaderOpts,
577591
RequireOSSAModules_t(Invocation.getSILOptions())));
578-
// If implicit modules are disabled, we need to install an explicit module
579-
// loader.
580-
bool ExplicitModuleBuild = Invocation.getFrontendOptions().DisableImplicitModules;
581-
if (ExplicitModuleBuild || !Invocation.getSearchPathOptions().ExplicitSwiftModuleMap.empty()) {
582-
auto ESML = ExplicitSwiftModuleLoader::create(
583-
*Context,
584-
getDependencyTracker(), MLM,
585-
Invocation.getSearchPathOptions().ExplicitSwiftModuleMap,
586-
IgnoreSourceInfoFile);
592+
593+
// Install an explicit module loader if it was created earlier.
594+
if (ESML) {
587595
this->DefaultSerializedLoader = ESML.get();
588596
Context->addModuleLoader(std::move(ESML));
589597
}

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,27 @@ struct ExplicitSwiftModuleLoader::Implementation {
18751875
else if (result == std::errc::no_such_file_or_directory)
18761876
Ctx.Diags.diagnose(SourceLoc(), diag::explicit_swift_module_map_missing,
18771877
fileName);
1878+
1879+
// A single module map can define multiple modules; keep track of the ones
1880+
// we've seen so that we don't generate duplicate flags.
1881+
std::set<std::string> moduleMapsSeen;
1882+
std::vector<std::string> &extraClangArgs = Ctx.ClangImporterOpts.ExtraArgs;
1883+
for (auto &entry : ExplicitModuleMap) {
1884+
const auto &moduleMapPath = entry.getValue().clangModuleMapPath;
1885+
if (!moduleMapPath.empty() &&
1886+
moduleMapsSeen.find(moduleMapPath) == moduleMapsSeen.end()) {
1887+
moduleMapsSeen.insert(moduleMapPath);
1888+
extraClangArgs.push_back(
1889+
(Twine("-fmodule-map-file=") + moduleMapPath).str());
1890+
}
1891+
1892+
const auto &modulePath = entry.getValue().clangModulePath;
1893+
if (!modulePath.empty()) {
1894+
extraClangArgs.push_back(
1895+
(Twine("-fmodule-file=") + entry.getKey() + "=" + modulePath)
1896+
.str());
1897+
}
1898+
}
18781899
}
18791900
};
18801901

@@ -1910,6 +1931,16 @@ bool ExplicitSwiftModuleLoader::findModule(ImportPath::Element ModuleID,
19101931
}
19111932
auto &moduleInfo = it->getValue();
19121933

1934+
// If this is only a Clang module with no paired Swift module, return false
1935+
// now so that we don't emit diagnostics about it being missing. This gives
1936+
// ClangImporter an opportunity to import it.
1937+
bool hasClangModule = !moduleInfo.clangModuleMapPath.empty() ||
1938+
!moduleInfo.clangModulePath.empty();
1939+
bool hasSwiftModule = !moduleInfo.modulePath.empty();
1940+
if (hasClangModule && !hasSwiftModule) {
1941+
return false;
1942+
}
1943+
19131944
// Set IsFramework bit according to the moduleInfo
19141945
IsFramework = moduleInfo.isFramework;
19151946
IsSystemModule = moduleInfo.isSystem;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/clang-module-cache
3+
// RUN: mkdir -p %t/inputs
4+
// RUN: echo "public func anotherFuncA() {}" > %t/A.swift
5+
// 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
6+
7+
// RUN: echo "[{" > %/t/inputs/map.json
8+
// RUN: echo "\"moduleName\": \"A\"," >> %/t/inputs/map.json
9+
// RUN: echo "\"modulePath\": \"%/t/inputs/A.swiftmodule\"," >> %/t/inputs/map.json
10+
// RUN: echo "\"docPath\": \"%/t/inputs/A.swiftdoc\"," >> %/t/inputs/map.json
11+
// RUN: echo "\"sourceInfoPath\": \"%/t/inputs/A.swiftsourceinfo\"," >> %/t/inputs/map.json
12+
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
13+
// RUN: echo "\"clangModuleMapPath\": \"%/S/Inputs/CHeaders/module.modulemap\"" >> %/t/inputs/map.json
14+
// RUN: echo "}," >> %/t/inputs/map.json
15+
// RUN: echo "{" >> %/t/inputs/map.json
16+
// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json
17+
// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json
18+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
19+
// RUN: echo "}," >> %/t/inputs/map.json
20+
// RUN: echo "{" >> %/t/inputs/map.json
21+
// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json
22+
// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json
23+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
24+
// RUN: echo "}," >> %/t/inputs/map.json
25+
// RUN: echo "{" >> %/t/inputs/map.json
26+
// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/inputs/map.json
27+
// RUN: echo "\"modulePath\": \"%/concurrency_module\"," >> %/t/inputs/map.json
28+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
29+
// RUN: echo "}," >> %/t/inputs/map.json
30+
// RUN: echo "{" >> %/t/inputs/map.json
31+
// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/inputs/map.json
32+
// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %/t/inputs/map.json
33+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
34+
// RUN: echo "}]" >> %/t/inputs/map.json
35+
36+
// 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
37+
38+
import A
39+
40+
func callA() {
41+
funcA()
42+
anotherFuncA()
43+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/clang-module-cache
3+
// RUN: mkdir -p %t/inputs
4+
5+
// RUN: echo "[{" > %/t/inputs/map.json
6+
// RUN: echo "\"moduleName\": \"A\"," >> %/t/inputs/map.json
7+
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
8+
// RUN: echo "\"clangModuleMapPath\": \"%/S/Inputs/CHeaders/module.modulemap\"," >> %/t/inputs/map.json
9+
// RUN: echo "\"clangModulePath\": \"%t/inputs/A.pcm\"" >> %/t/inputs/map.json
10+
// RUN: echo "}," >> %/t/inputs/map.json
11+
// RUN: echo "{" >> %/t/inputs/map.json
12+
// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json
13+
// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json
14+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
15+
// RUN: echo "}," >> %/t/inputs/map.json
16+
// RUN: echo "{" >> %/t/inputs/map.json
17+
// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json
18+
// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json
19+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
20+
// RUN: echo "}," >> %/t/inputs/map.json
21+
// RUN: echo "{" >> %/t/inputs/map.json
22+
// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/inputs/map.json
23+
// RUN: echo "\"modulePath\": \"%/concurrency_module\"," >> %/t/inputs/map.json
24+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
25+
// RUN: echo "}," >> %/t/inputs/map.json
26+
// RUN: echo "{" >> %/t/inputs/map.json
27+
// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/inputs/map.json
28+
// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %/t/inputs/map.json
29+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
30+
// RUN: echo "}]" >> %/t/inputs/map.json
31+
32+
// RUN: %target-swift-emit-pcm -module-name A -o %t/inputs/A.pcm %S/Inputs/CHeaders/module.modulemap
33+
// 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
34+
35+
import A
36+
37+
func callA() {
38+
funcA()
39+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/clang-module-cache
3+
// RUN: mkdir -p %t/inputs
4+
5+
// RUN: echo "[{" > %/t/inputs/map.json
6+
// RUN: echo "\"moduleName\": \"A\"," >> %/t/inputs/map.json
7+
// RUN: echo "\"isFramework\": false," >> %/t/inputs/map.json
8+
// RUN: echo "\"clangModuleMapPath\": \"%/S/Inputs/CHeaders/module.modulemap\"" >> %/t/inputs/map.json
9+
// RUN: echo "}," >> %/t/inputs/map.json
10+
// RUN: echo "{" >> %/t/inputs/map.json
11+
// RUN: echo "\"moduleName\": \"Swift\"," >> %/t/inputs/map.json
12+
// RUN: echo "\"modulePath\": \"%/stdlib_module\"," >> %/t/inputs/map.json
13+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
14+
// RUN: echo "}," >> %/t/inputs/map.json
15+
// RUN: echo "{" >> %/t/inputs/map.json
16+
// RUN: echo "\"moduleName\": \"SwiftOnoneSupport\"," >> %/t/inputs/map.json
17+
// RUN: echo "\"modulePath\": \"%/ononesupport_module\"," >> %/t/inputs/map.json
18+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
19+
// RUN: echo "}," >> %/t/inputs/map.json
20+
// RUN: echo "{" >> %/t/inputs/map.json
21+
// RUN: echo "\"moduleName\": \"_Concurrency\"," >> %/t/inputs/map.json
22+
// RUN: echo "\"modulePath\": \"%/concurrency_module\"," >> %/t/inputs/map.json
23+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
24+
// RUN: echo "}," >> %/t/inputs/map.json
25+
// RUN: echo "{" >> %/t/inputs/map.json
26+
// RUN: echo "\"moduleName\": \"_StringProcessing\"," >> %/t/inputs/map.json
27+
// RUN: echo "\"modulePath\": \"%/string_processing_module\"," >> %/t/inputs/map.json
28+
// RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json
29+
// RUN: echo "}]" >> %/t/inputs/map.json
30+
31+
// 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
32+
33+
import A
34+
35+
func callA() {
36+
funcA()
37+
}

0 commit comments

Comments
 (0)