Skip to content

Commit 6420013

Browse files
committed
Implement --enable-parseable-module-interfaces for swift-build buildsystem
- this also fixes -enable-library-evolution when used as a unsafeFlags Closes: 8337
1 parent adc2535 commit 6420013

File tree

2 files changed

+91
-67
lines changed

2 files changed

+91
-67
lines changed

Sources/SwiftBuildSupport/SwiftBuildSystem.swift

+5
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,11 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
470470
settings["ARCHS"] = architectures.joined(separator: " ")
471471
}
472472

473+
// support for --enable-parseable-module-interfaces
474+
if buildParameters.driverParameters.enableParseableModuleInterfaces {
475+
settings["SWIFT_EMIT_MODULE_INTERFACE"] = "YES"
476+
}
477+
473478
// Generate the build parameters.
474479
var params = SwiftBuild.SWBBuildParameters()
475480
params.configurationName = buildParameters.configuration.swiftbuildName

Tests/CommandsTests/BuildCommandTests.swift

+86-67
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class BuildCommandTestCases: CommandsBuildProviderTestCase {
3838
}
3939

4040
@discardableResult
41-
private func execute(
41+
func execute(
4242
_ args: [String] = [],
4343
environment: Environment? = nil,
4444
packagePath: AbsolutePath? = nil
@@ -70,7 +70,19 @@ class BuildCommandTestCases: CommandsBuildProviderTestCase {
7070
// is what `binContents` is meant to represent.
7171
return contents != ["output-file-map.json"]
7272
}
73-
let moduleContents = (try? localFileSystem.getDirectoryContents(binPath.appending(component: "Modules"))) ?? []
73+
var moduleContents: [String] = []
74+
if buildSystemProvider == .native {
75+
moduleContents = (try? localFileSystem.getDirectoryContents(binPath.appending(component: "Modules"))) ?? []
76+
} else {
77+
let moduleDirs = (try? localFileSystem.getDirectoryContents(binPath).filter {
78+
$0.hasSuffix(".swiftmodule")
79+
}) ?? []
80+
for dir: String in moduleDirs {
81+
moduleContents +=
82+
(try? localFileSystem.getDirectoryContents(binPath.appending(component: dir)).map { "\(dir)/\($0)" }) ?? []
83+
}
84+
}
85+
7486

7587
if cleanAfterward {
7688
try! await executeSwiftPackage(
@@ -103,6 +115,10 @@ class BuildCommandTestCases: CommandsBuildProviderTestCase {
103115
XCTAssertMatch(stdout, .contains("USAGE: swift build"))
104116
}
105117

118+
func testBinSymlink() async throws {
119+
XCTAssertTrue(false, "Must be implemented at build system test class.")
120+
}
121+
106122
func testSeeAlso() async throws {
107123
let stdout = try await execute(["--help"]).stdout
108124
XCTAssertMatch(stdout, .contains("SEE ALSO: swift run, swift package, swift test"))
@@ -190,48 +206,6 @@ class BuildCommandTestCases: CommandsBuildProviderTestCase {
190206
}
191207
}
192208

193-
func testBinSymlink() async throws {
194-
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
195-
let fullPath = try resolveSymlinks(fixturePath)
196-
let targetPath = try fullPath.appending(
197-
components: ".build",
198-
UserToolchain.default.targetTriple.platformBuildPathComponent
199-
)
200-
let xcbuildTargetPath = fullPath.appending(components: ".build", "apple")
201-
try await XCTAssertAsyncEqual(
202-
try await self.execute(["--show-bin-path"], packagePath: fullPath).stdout,
203-
"\(targetPath.appending("debug").pathString)\n"
204-
)
205-
try await XCTAssertAsyncEqual(
206-
try await self.execute(["-c", "release", "--show-bin-path"], packagePath: fullPath).stdout,
207-
"\(targetPath.appending("release").pathString)\n"
208-
)
209-
210-
guard buildSystemProvider == .xcode || buildSystemProvider == .swiftbuild else {
211-
// The remainder of this test only applies to XCBuild or Swift Build
212-
return
213-
}
214-
215-
// Print correct path when building with XCBuild or Swift Build
216-
let xcodeDebugOutput = try await execute(
217-
["-c", "debug", "--show-bin-path"],
218-
packagePath: fullPath)
219-
.stdout
220-
let xcodeReleaseOutput = try await execute(
221-
["-c", "release", "--show-bin-path"],
222-
packagePath: fullPath
223-
).stdout
224-
XCTAssertEqual(
225-
xcodeDebugOutput,
226-
"\(xcbuildTargetPath.appending(components: "Products", "Debug").pathString)\n"
227-
)
228-
XCTAssertEqual(
229-
xcodeReleaseOutput,
230-
"\(xcbuildTargetPath.appending(components: "Products", "Release").pathString)\n"
231-
)
232-
}
233-
}
234-
235209
func testSymlink() async throws {
236210
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
237211
let fullPath = try resolveSymlinks(fixturePath)
@@ -792,6 +766,25 @@ class BuildCommandNativeTests: BuildCommandTestCases {
792766
override func testUsage() async throws {
793767
try await super.testUsage()
794768
}
769+
770+
override func testBinSymlink() async throws {
771+
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
772+
let fullPath = try resolveSymlinks(fixturePath)
773+
let targetPath = try fullPath.appending(
774+
components: ".build",
775+
UserToolchain.default.targetTriple.platformBuildPathComponent
776+
)
777+
try await XCTAssertAsyncEqual(
778+
try await self.execute(["--show-bin-path"], packagePath: fullPath).stdout,
779+
"\(targetPath.appending("debug").pathString)\n"
780+
)
781+
try await XCTAssertAsyncEqual(
782+
try await self.execute(["-c", "release", "--show-bin-path"], packagePath: fullPath)
783+
.stdout,
784+
"\(targetPath.appending("release").pathString)\n"
785+
)
786+
}
787+
}
795788
}
796789

797790
#if os(macOS)
@@ -806,51 +799,51 @@ class BuildCommandXcodeTests: BuildCommandTestCases {
806799
}
807800

808801
override func testAutomaticParseableInterfacesWithLibraryEvolution() async throws {
809-
try XCTSkip("Test not implemented for xcode build system.")
802+
throw XCTSkip("Test not implemented for xcode build system.")
810803
}
811804

812805
override func testNonReachableProductsAndTargetsFunctional() async throws {
813-
try XCTSkip("Test not implemented for xcode build system.")
806+
throw XCTSkip("Test not implemented for xcode build system.")
814807
}
815808

816809
override func testCodeCoverage() async throws {
817-
try XCTSkip("Test not implemented for xcode build system.")
810+
throw XCTSkip("Test not implemented for xcode build system.")
818811
}
819812

820813
override func testBuildStartMessage() async throws {
821-
try XCTSkip("Test not implemented for xcode build system.")
814+
throw XCTSkip("Test not implemented for xcode build system.")
822815
}
823816

824817
override func testBinSymlink() async throws {
825-
try XCTSkip("Test not implemented for xcode build system.")
818+
throw XCTSkip("Test not implemented for xcode build system.")
826819
}
827820

828821
override func testSymlink() async throws {
829-
try XCTSkip("Test not implemented for xcode build system.")
822+
throw XCTSkip("Test not implemented for xcode build system.")
830823
}
831824

832825
override func testSwiftGetVersion() async throws {
833-
try XCTSkip("Test not implemented for xcode build system.")
826+
throw XCTSkip("Test not implemented for xcode build system.")
834827
}
835828

836829
override func testParseableInterfaces() async throws {
837-
try XCTSkip("Test not implemented for xcode build system.")
830+
throw XCTSkip("Test not implemented for xcode build system.")
838831
}
839832

840833
override func testProductAndTarget() async throws {
841-
try XCTSkip("Test not implemented for xcode build system.")
834+
throw XCTSkip("Test not implemented for xcode build system.")
842835
}
843836

844837
override func testImportOfMissedDepWarning() async throws {
845-
try XCTSkip("Test not implemented for xcode build system.")
838+
throw XCTSkip("Test not implemented for xcode build system.")
846839
}
847840

848841
override func testGetTaskAllowEntitlement() async throws {
849-
try XCTSkip("Test not implemented for xcode build system.")
842+
throw XCTSkip("Test not implemented for xcode build system.")
850843
}
851844

852845
override func testBuildCompleteMessage() async throws {
853-
try XCTSkip("Test not implemented for xcode build system.")
846+
throw XCTSkip("Test not implemented for xcode build system.")
854847
}
855848
}
856849
#endif
@@ -866,9 +859,31 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
866859
}
867860

868861
override func testParseableInterfaces() async throws {
869-
throw XCTSkip("SWBINTTODO: Test failed with swiftbuild engine because the --enable-parseable-module-interfaces flag doesn't yet produce .swiftinterface files. This needs to be investigated")
862+
try await fixture(name: "Miscellaneous/ParseableInterfaces") { fixturePath in
863+
do {
864+
let result = try await build(["--enable-parseable-module-interfaces"], packagePath: fixturePath)
865+
XCTAssertMatch(result.moduleContents, [.regex(#"A\.swiftmodule\/.*\.swiftinterface"#)])
866+
XCTAssertMatch(result.moduleContents, [.regex(#"B\.swiftmodule\/.*\.swiftmodule"#)])
867+
} catch SwiftPMError.executionFailure(_, _, let stderr) {
868+
XCTFail(stderr)
869+
}
870+
}
870871
}
871872

873+
override func testBinSymlink() async throws {
874+
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
875+
let fullPath = try resolveSymlinks(fixturePath)
876+
let targetPath = try fullPath.appending(
877+
components: ".build",
878+
UserToolchain.default.targetTriple.platformBuildPathComponent
879+
)
880+
let debugPath = try await self.execute(["--show-bin-path"], packagePath: fullPath).stdout
881+
XCTAssertMatch(debugPath, .regex(targetPath.appending(components: "Products", "Debug").pathString + "(\\-linux|\\-Windows)?\\n"))
882+
let releasePath = try await self.execute(["-c", "release", "--show-bin-path"], packagePath: fullPath).stdout
883+
XCTAssertMatch(releasePath, .regex(targetPath.appending(components: "Products", "Release").pathString + "(\\-linux|\\-Windows)?\\n"))
884+
}
885+
}
886+
872887
override func testGetTaskAllowEntitlement() async throws {
873888
throw XCTSkip("SWBINTTODO: Test failed because swiftbuild doesn't output precis codesign commands. Once swift run works with swiftbuild the test can be investigated.")
874889
}
@@ -880,13 +895,20 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
880895
override func testAtMainSupport() async throws {
881896
#if !os(macOS)
882897
throw XCTSkip("SWBINTTODO: File not found or missing libclang errors on non-macOS platforms. This needs to be investigated")
883-
#endif
884-
898+
#else
885899
try await super.testAtMainSupport()
900+
#endif
886901
}
887902

888903
override func testAutomaticParseableInterfacesWithLibraryEvolution() async throws {
889-
throw XCTSkip("SWBINTTODO: The test fails because when the unsafe flag for a target is set to '-enable-library-evolution' it is not producing the correct .swiftinterface files. This needs to be investigated")
904+
try await fixture(name: "Miscellaneous/LibraryEvolution") { fixturePath in
905+
do {
906+
let result = try await build([], packagePath: fixturePath)
907+
XCTAssertMatch(
908+
result.moduleContents, [.regex(#"A\.swiftmodule\/.*\.swiftinterface"#)])
909+
XCTAssertMatch(result.moduleContents, [.regex(#"B\.swiftmodule\/.*\.swiftmodule"#)])
910+
}
911+
}
890912
}
891913

892914
override func testImportOfMissedDepWarning() async throws {
@@ -901,10 +923,6 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
901923
throw XCTSkip("SWBINTTODO: Test fails because the dummy-swiftc used in the test isn't accepted by swift-build. This needs to be investigated")
902924
}
903925

904-
override func testBinSymlink() async throws {
905-
throw XCTSkip("SWBINTTODO: Test fails because of a difference in the build layout. This needs to be updated to the expected path")
906-
}
907-
908926
override func testSymlink() async throws {
909927
throw XCTSkip("SWBINTTODO: Test fails because of a difference in the build layout. This needs to be updated to the expected path")
910928
}
@@ -927,7 +945,7 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
927945

928946
override func testBuildSystemDefaultSettings() async throws {
929947
#if os(Linux)
930-
if FileManager.default.contents(atPath: "/etc/system-release").map { String(decoding: $0, as: UTF8.self) == "Amazon Linux release 2 (Karoo)\n" } ?? false {
948+
if FileManager.default.contents(atPath: "/etc/system-release").map( { String(decoding: $0, as: UTF8.self) == "Amazon Linux release 2 (Karoo)\n" } ) ?? false {
931949
throw XCTSkip("Skipping SwiftBuild testing on Amazon Linux because of platform issues.")
932950
}
933951
#endif
@@ -941,9 +959,10 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
941959

942960
override func testBuildCompleteMessage() async throws {
943961
#if os(Linux)
944-
try XCTSkip("SWBINTTODO: Need to properly set LD_LIBRARY_PATH on linux")
945-
#endif
962+
throw XCTSkip("SWBINTTODO: Need to properly set LD_LIBRARY_PATH on linux")
963+
#else
946964
try await super.testBuildCompleteMessage()
965+
#endif
947966
}
948967

949968
}

0 commit comments

Comments
 (0)