Skip to content

Commit 395acee

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 2dc064d commit 395acee

File tree

3 files changed

+85
-67
lines changed

3 files changed

+85
-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

Sources/_InternalTestSupport/SwiftPMProduct.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ extension SwiftPM {
9797

9898
let returnValue = (stdout: stdout, stderr: stderr)
9999
if (!throwIfCommandFails) { return returnValue }
100-
100+
// print("STDOUT:\n\(stdout)")
101+
// print("STDER:\n\(stderr)")
101102
if result.exitStatus == .terminated(code: 0) {
102103
return returnValue
103104
}
@@ -142,6 +143,7 @@ extension SwiftPM {
142143
completeArgs += ["--package-path", packagePath.pathString]
143144
}
144145
completeArgs += args
146+
// print("EXE:\(completeArgs)")
145147

146148
return try await AsyncProcess.popen(arguments: completeArgs, environment: environment)
147149
}

Tests/CommandsTests/BuildCommandTests.swift

+77-66
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,18 @@ 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+
return $0.hasSuffix(".swiftmodule")
79+
}) ?? []
80+
for dir: String in moduleDirs {
81+
moduleContents += (try? localFileSystem.getDirectoryContents(binPath.appending(component: dir)).map { "\(dir)/\($0)" }) ?? []
82+
}
83+
}
84+
7485

7586
if cleanAfterward {
7687
try! await executeSwiftPackage(
@@ -190,48 +201,6 @@ class BuildCommandTestCases: CommandsBuildProviderTestCase {
190201
}
191202
}
192203

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-
235204
func testSymlink() async throws {
236205
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
237206
let fullPath = try resolveSymlinks(fixturePath)
@@ -792,6 +761,24 @@ class BuildCommandNativeTests: BuildCommandTestCases {
792761
override func testUsage() async throws {
793762
try await super.testUsage()
794763
}
764+
765+
func testBinSymlink() async throws {
766+
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
767+
let fullPath = try resolveSymlinks(fixturePath)
768+
let targetPath = try fullPath.appending(
769+
components: ".build",
770+
UserToolchain.default.targetTriple.platformBuildPathComponent
771+
)
772+
try await XCTAssertAsyncEqual(
773+
try await self.execute(["--show-bin-path"], packagePath: fullPath).stdout,
774+
"\(targetPath.appending("debug").pathString)\n"
775+
)
776+
try await XCTAssertAsyncEqual(
777+
try await self.execute(["-c", "release", "--show-bin-path"], packagePath: fullPath).stdout,
778+
"\(targetPath.appending("release").pathString)\n"
779+
)
780+
}
781+
}
795782
}
796783

797784
#if os(macOS)
@@ -806,47 +793,47 @@ class BuildCommandXcodeTests: BuildCommandTestCases {
806793
}
807794

808795
override func testAutomaticParseableInterfacesWithLibraryEvolution() async throws {
809-
try XCTSkip("Test not implemented for xcode build system.")
796+
throw XCTSkip("Test not implemented for xcode build system.")
810797
}
811798

812799
override func testNonReachableProductsAndTargetsFunctional() async throws {
813-
try XCTSkip("Test not implemented for xcode build system.")
800+
throw XCTSkip("Test not implemented for xcode build system.")
814801
}
815802

816803
override func testCodeCoverage() async throws {
817-
try XCTSkip("Test not implemented for xcode build system.")
804+
throw XCTSkip("Test not implemented for xcode build system.")
818805
}
819806

820807
override func testBuildStartMessage() async throws {
821-
try XCTSkip("Test not implemented for xcode build system.")
808+
throw XCTSkip("Test not implemented for xcode build system.")
822809
}
823810

824-
override func testBinSymlink() async throws {
825-
try XCTSkip("Test not implemented for xcode build system.")
811+
func testBinSymlink() async throws {
812+
throw XCTSkip("Test not implemented for xcode build system.")
826813
}
827814

828815
override func testSymlink() async throws {
829-
try XCTSkip("Test not implemented for xcode build system.")
816+
throw XCTSkip("Test not implemented for xcode build system.")
830817
}
831818

832819
override func testSwiftGetVersion() async throws {
833-
try XCTSkip("Test not implemented for xcode build system.")
820+
throw XCTSkip("Test not implemented for xcode build system.")
834821
}
835822

836823
override func testParseableInterfaces() async throws {
837-
try XCTSkip("Test not implemented for xcode build system.")
824+
throw XCTSkip("Test not implemented for xcode build system.")
838825
}
839826

840827
override func testProductAndTarget() async throws {
841-
try XCTSkip("Test not implemented for xcode build system.")
828+
throw XCTSkip("Test not implemented for xcode build system.")
842829
}
843830

844831
override func testImportOfMissedDepWarning() async throws {
845-
try XCTSkip("Test not implemented for xcode build system.")
832+
throw XCTSkip("Test not implemented for xcode build system.")
846833
}
847834

848835
override func testGetTaskAllowEntitlement() async throws {
849-
try XCTSkip("Test not implemented for xcode build system.")
836+
throw XCTSkip("Test not implemented for xcode build system.")
850837
}
851838

852839
override func testBuildCompleteMessage() async throws {
@@ -861,14 +848,36 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
861848
return .swiftbuild
862849
}
863850

864-
override func testNonReachableProductsAndTargetsFunctional() async throws {
865-
throw XCTSkip("SWBINTTODO: Test failed. This needs to be investigated")
866-
}
867-
868851
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")
852+
try await fixture(name: "Miscellaneous/ParseableInterfaces") { fixturePath in
853+
do {
854+
let result = try await build(["--enable-parseable-module-interfaces"], packagePath: fixturePath)
855+
XCTAssertMatch(result.moduleContents, [.regex(#"A\.swiftmodule\/.*\.swiftinterface"#)])
856+
XCTAssertMatch(result.moduleContents, [.regex(#"B\.swiftmodule\/.*\.swiftmodule"#)])
857+
} catch SwiftPMError.executionFailure(_, _, let stderr) {
858+
XCTFail(stderr)
859+
}
860+
}
870861
}
871862

863+
func testBinSymlink() async throws {
864+
try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in
865+
let fullPath = try resolveSymlinks(fixturePath)
866+
let targetPath = try fullPath.appending(
867+
components: ".build",
868+
UserToolchain.default.targetTriple.platformBuildPathComponent
869+
)
870+
try await XCTAssertAsyncEqual(
871+
try await self.execute(["--show-bin-path"], packagePath: fullPath).stdout,
872+
"\(targetPath.appending(components: "Products", "Debug").pathString)\n"
873+
)
874+
try await XCTAssertAsyncEqual(
875+
try await self.execute(["-c", "release", "--show-bin-path"], packagePath: fullPath).stdout,
876+
"\(targetPath.appending(components: "Products", "Release").pathString)\n"
877+
)
878+
}
879+
}
880+
872881
override func testGetTaskAllowEntitlement() async throws {
873882
throw XCTSkip("SWBINTTODO: Test failed because swiftbuild doesn't output precis codesign commands. Once swift run works with swiftbuild the test can be investigated.")
874883
}
@@ -886,7 +895,13 @@ class BuildCommandSwiftBuildTests: BuildCommandTestCases {
886895
}
887896

888897
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")
898+
try await fixture(name: "Miscellaneous/LibraryEvolution") { fixturePath in
899+
do {
900+
let result = try await build([], packagePath: fixturePath)
901+
XCTAssertMatch(result.moduleContents, [.regex(#"A\.swiftmodule\/.*\.swiftinterface"#)])
902+
XCTAssertMatch(result.moduleContents, [.regex(#"B\.swiftmodule\/.*\.swiftmodule"#)])
903+
}
904+
}
890905
}
891906

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

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-
908919
override func testSymlink() async throws {
909920
throw XCTSkip("SWBINTTODO: Test fails because of a difference in the build layout. This needs to be updated to the expected path")
910921
}

0 commit comments

Comments
 (0)