Skip to content

Commit 58eb4ce

Browse files
authored
Allow C targets to import the compatibility header generated for Swift libraries (#8736)
Address two issues preventing a C source file to import the generated compatibility header: 1. Don't mark the module map generated for the compatibility header as `requires objc`. This triggers an error when importing it from a C source file. The compatibility header is already printed in a way where the Objective-C code is protected behind a language check. C clients can safely import it even if they may not see any content. Plus we're adding C content to the compatibility header with the official support for `@cdecl` that is independent of Objective-C. 2. Emit the generated compatibility header and module map in a new `include` directory under the temporary build directory of each Swift library. This directory is then used as a header search path for the dependent clang targets. This replaces the previous strategy that relied only the generated module map to resolve imports. It was incompatible with C source files and non-modular textual includes. The use of a header search path preserves the support for module imports via the same module map and supports textual includes of the compatibility header. Fixes #7257. Follow up to #8695.
1 parent adf14cf commit 58eb4ce

File tree

4 files changed

+23
-19
lines changed

4 files changed

+23
-19
lines changed

Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -910,15 +910,20 @@ public final class SwiftModuleBuildDescription {
910910
try self.fileSystem.writeFileContents(path, bytes: .init(encodingAsUTF8: content), atomically: true)
911911
}
912912

913+
/// Directory for the the compatibility header and module map generated for this target.
914+
/// The whole directory should be usable as a header search path.
915+
private var compatibilityHeaderDirectory: AbsolutePath {
916+
tempsPath.appending("include")
917+
}
918+
913919
/// Generates the module map for the Swift target and returns its path.
914920
private func generateModuleMap() throws -> AbsolutePath {
915-
let path = self.tempsPath.appending(component: moduleMapFilename)
921+
let path = self.compatibilityHeaderDirectory.appending(component: moduleMapFilename)
916922

917923
let bytes = ByteString(
918924
#"""
919925
module \#(self.target.c99name) {
920926
header "\#(self.objCompatibilityHeaderPath.pathString)"
921-
requires objc
922927
}
923928
924929
"""#.utf8
@@ -937,7 +942,7 @@ public final class SwiftModuleBuildDescription {
937942

938943
/// Returns the path to the ObjC compatibility header for this Swift target.
939944
var objCompatibilityHeaderPath: AbsolutePath {
940-
self.tempsPath.appending("\(self.target.name)-Swift.h")
945+
self.compatibilityHeaderDirectory.appending("\(self.target.name)-Swift.h")
941946
}
942947

943948
/// Returns the build flags from the declared build settings.

Sources/Build/BuildPlan/BuildPlan+Clang.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ extension BuildPlan {
3030
case is SwiftModule:
3131
if case let .swift(dependencyTargetDescription)? = description {
3232
if let moduleMap = dependencyTargetDescription.moduleMap {
33-
clangTarget.additionalFlags += ["-fmodule-map-file=\(moduleMap.pathString)"]
33+
// C languages clients should either import the module or include the compatibility header next to it.
34+
clangTarget.additionalFlags += ["-I", moduleMap.dirname]
3435
}
3536
}
3637

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,7 +2029,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
20292029

20302030
// D
20312031
do {
2032-
let expectedBModuleMap = AbsolutePath("/path/to/build/\(triple)/debug/B.build/module.modulemap").pathString
2032+
let expectedBInclude = AbsolutePath("/path/to/build/\(triple)/debug/B.build/include").pathString
20332033
let expectedCModuleMap = AbsolutePath("/path/to/build/\(triple)/debug/C.build/module.modulemap").pathString
20342034
let expectedDModuleMap = AbsolutePath("/path/to/build/\(triple)/debug/D.build/module.modulemap").pathString
20352035
let expectedModuleCache = AbsolutePath("/path/to/build/\(triple)/debug/ModuleCache").pathString
@@ -2051,13 +2051,11 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
20512051
]
20522052
)
20532053

2054-
#if os(macOS)
20552054
try XCTAssertMatchesSubSequences(
20562055
result.moduleBuildDescription(for: "D").symbolGraphExtractArguments(),
20572056
// Swift Module dependencies
2058-
["-Xcc", "-fmodule-map-file=\(expectedBModuleMap)"]
2057+
["-Xcc", "-I", "-Xcc", "\(expectedBInclude)"]
20592058
)
2060-
#endif
20612059
}
20622060
}
20632061

@@ -5981,7 +5979,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
59815979
.anySequence,
59825980
"-emit-objc-header",
59835981
"-emit-objc-header-path",
5984-
"\(buildPath.appending(components: "Foo.build", "Foo-Swift.h"))",
5982+
"\(buildPath.appending(components: "Foo.build", "include", "Foo-Swift.h"))",
59855983
.anySequence,
59865984
]
59875985
)
@@ -5991,7 +5989,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
59915989
barTarget,
59925990
[
59935991
.anySequence,
5994-
"-fmodule-map-file=\(buildPath.appending(components: "Foo.build", "module.modulemap"))",
5992+
"-I", "\(buildPath.appending(components: "Foo.build", "include"))",
59955993
.anySequence,
59965994
]
59975995
)
@@ -6066,7 +6064,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
60666064
.anySequence,
60676065
"-emit-objc-header",
60686066
"-emit-objc-header-path",
6069-
"\(buildPath.appending(components: "Foo.build", "Foo-Swift.h"))",
6067+
"\(buildPath.appending(components: "Foo.build", "include", "Foo-Swift.h"))",
60706068
.anySequence,
60716069
]
60726070
)
@@ -6076,7 +6074,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
60766074
barTarget,
60776075
[
60786076
.anySequence,
6079-
"-fmodule-map-file=\(buildPath.appending(components: "Foo.build", "module.modulemap"))",
6077+
"-I", "\(buildPath.appending(components: "Foo.build", "include"))",
60806078
.anySequence,
60816079
]
60826080
)
@@ -6156,7 +6154,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
61566154
.anySequence,
61576155
"-emit-objc-header",
61586156
"-emit-objc-header-path",
6159-
"\(buildPath.appending(components: "Foo.build", "Foo-Swift.h"))",
6157+
"\(buildPath.appending(components: "Foo.build", "include", "Foo-Swift.h"))",
61606158
.anySequence,
61616159
]
61626160
)
@@ -6166,7 +6164,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
61666164
barTarget,
61676165
[
61686166
.anySequence,
6169-
"-fmodule-map-file=\(buildPath.appending(components: "Foo.build", "module.modulemap"))",
6167+
"-I", "\(buildPath.appending(components: "Foo.build", "include"))",
61706168
.anySequence,
61716169
]
61726170
)

Tests/BuildTests/ModuleAliasingBuildTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -737,19 +737,19 @@ final class ModuleAliasingBuildTests: XCTestCase {
737737
XCTAssertMatch(
738738
fooLoggingArgs,
739739
[.anySequence, "-emit-objc-header", "-emit-objc-header-path",
740-
"\(buildPath.appending(components: "FooLogging.build", "FooLogging-Swift.h"))",
740+
"\(buildPath.appending(components: "FooLogging.build", "include", "FooLogging-Swift.h"))",
741741
.anySequence]
742742
)
743743
XCTAssertMatch(
744744
barLoggingArgs,
745745
[.anySequence, "-emit-objc-header", "-emit-objc-header-path",
746-
"\(buildPath.appending(components: "BarLogging.build", "BarLogging-Swift.h"))",
746+
"\(buildPath.appending(components: "BarLogging.build", "include", "BarLogging-Swift.h"))",
747747
.anySequence]
748748
)
749749
XCTAssertMatch(
750750
loggingArgs,
751751
[.anySequence, "-emit-objc-header", "-emit-objc-header-path",
752-
"\(buildPath.appending(components: "Logging.build", "Logging-Swift.h"))",
752+
"\(buildPath.appending(components: "Logging.build", "include", "Logging-Swift.h"))",
753753
.anySequence]
754754
)
755755
}
@@ -843,13 +843,13 @@ final class ModuleAliasingBuildTests: XCTestCase {
843843
XCTAssertMatch(
844844
otherLoggingArgs,
845845
[.anySequence, "-emit-objc-header", "-emit-objc-header-path",
846-
"\(buildPath.appending(components: "OtherLogging.build", "OtherLogging-Swift.h"))",
846+
"\(buildPath.appending(components: "OtherLogging.build", "include", "OtherLogging-Swift.h"))",
847847
.anySequence]
848848
)
849849
XCTAssertMatch(
850850
loggingArgs,
851851
[.anySequence, "-emit-objc-header", "-emit-objc-header-path",
852-
"\(buildPath.appending(components: "Logging.build", "Logging-Swift.h"))",
852+
"\(buildPath.appending(components: "Logging.build", "include", "Logging-Swift.h"))",
853853
.anySequence]
854854
)
855855
}

0 commit comments

Comments
 (0)