diff --git a/Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Foo.swift b/Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Foo.swift new file mode 100644 index 00000000000..aeeb2c29b21 --- /dev/null +++ b/Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Foo.swift @@ -0,0 +1,8 @@ +@available(macOS, obsoleted: 13.0) +func foo() { + +} + +func bar() { + foo() +} diff --git a/Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Package.swift b/Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Package.swift new file mode 100644 index 00000000000..220ca90d3a9 --- /dev/null +++ b/Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Package.swift @@ -0,0 +1,13 @@ +// swift-tools-version:6.1 +import PackageDescription + +let package = Package( + name: "Foo", + platforms: [.macOS(.v12)], + products: [ + .library(name: "Foo", targets: ["Foo"]), + ], + targets: [ + .target(name: "Foo", path: "./"), + ] +) diff --git a/Sources/Basics/Triple+Basics.swift b/Sources/Basics/Triple+Basics.swift index 9773457033b..710d9900404 100644 --- a/Sources/Basics/Triple+Basics.swift +++ b/Sources/Basics/Triple+Basics.swift @@ -85,7 +85,16 @@ extension Triple { } /// Determine the versioned host triple using the Swift compiler. - public static func getHostTriple(usingSwiftCompiler swiftCompiler: AbsolutePath) throws -> Triple { + public static func getVersionedHostTriple(usingSwiftCompiler swiftCompiler: AbsolutePath) throws -> Triple { + try Self.getHostTriple(usingSwiftCompiler: swiftCompiler, versioned: true) + } + + /// Determine the unversioned host triple using the Swift compiler. + public static func getUnversionedHostTriple(usingSwiftCompiler swiftCompiler: AbsolutePath) throws -> Triple { + try Self.getHostTriple(usingSwiftCompiler: swiftCompiler, versioned: false) + } + + private static func getHostTriple(usingSwiftCompiler swiftCompiler: AbsolutePath, versioned: Bool) throws -> Triple { // Call the compiler to get the target info JSON. let compilerOutput: String do { @@ -106,7 +115,7 @@ extension Triple { // Get the triple string from the parsed JSON. let tripleString: String do { - tripleString = try parsedTargetInfo.get("target").get("triple") + tripleString = try parsedTargetInfo.get("target").get(versioned ? "triple" : "unversionedTriple") } catch { throw InternalError( "Target info does not contain a triple string (\(error.interpolationDescription)).\nTarget info: \(parsedTargetInfo)" diff --git a/Sources/Commands/PackageCommands/AuditBinaryArtifact.swift b/Sources/Commands/PackageCommands/AuditBinaryArtifact.swift index 0b5119fe733..ac290eea4c0 100644 --- a/Sources/Commands/PackageCommands/AuditBinaryArtifact.swift +++ b/Sources/Commands/PackageCommands/AuditBinaryArtifact.swift @@ -37,7 +37,7 @@ struct AuditBinaryArtifact: AsyncSwiftCommand { let hostToolchain = try swiftCommandState.getHostToolchain() let clang = try hostToolchain.getClangCompiler() let objdump = try hostToolchain.getLLVMObjdump() - let hostTriple = try Triple.getHostTriple( + let hostTriple = try Triple.getVersionedHostTriple( usingSwiftCompiler: hostToolchain.swiftCompilerPath) let fileSystem = swiftCommandState.fileSystem diff --git a/Sources/PackageModel/UserToolchain.swift b/Sources/PackageModel/UserToolchain.swift index 3d9bf6797e8..86149e2d997 100644 --- a/Sources/PackageModel/UserToolchain.swift +++ b/Sources/PackageModel/UserToolchain.swift @@ -200,11 +200,11 @@ public final class UserToolchain: Toolchain { } } - private static func getHostTriple(targetInfo: JSON) throws -> Basics.Triple { + private static func getHostTriple(targetInfo: JSON, versioned: Bool) throws -> Basics.Triple { // Get the triple string from the target info. let tripleString: String do { - tripleString = try targetInfo.get("target").get("triple") + tripleString = try targetInfo.get("target").get(versioned ? "triple" : "unversionedTriple") } catch { throw InternalError( "Target info does not contain a triple string (\(error.interpolationDescription)).\nTarget info: \(targetInfo)" @@ -741,7 +741,7 @@ public final class UserToolchain: Toolchain { // targetInfo from the compiler let targetInfo = try customTargetInfo ?? Self.getTargetInfo(swiftCompiler: swiftCompilers.compile) self._targetInfo = targetInfo - triple = try swiftSDK.targetTriple ?? Self.getHostTriple(targetInfo: targetInfo) + triple = try swiftSDK.targetTriple ?? Self.getHostTriple(targetInfo: targetInfo, versioned: false) } // Change the triple to the specified arch if there's exactly one of them. diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index 6bd5b8804c1..56bc1254984 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -173,7 +173,8 @@ public struct BuildParameters: Encodable { testingParameters: Testing = .init(), apiDigesterMode: APIDigesterMode? = nil ) throws { - let triple = try triple ?? .getHostTriple(usingSwiftCompiler: toolchain.swiftCompilerPath) + // Default to the unversioned triple if none is provided so that we defer to the package's requested deployment target. + let triple = try triple ?? .getUnversionedHostTriple(usingSwiftCompiler: toolchain.swiftCompilerPath) self.debuggingParameters = debuggingParameters ?? .init( triple: triple, shouldEnableDebuggingEntitlement: configuration == .debug, diff --git a/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift b/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift index f8a98a664e5..c1f487c7bba 100644 --- a/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift +++ b/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift @@ -466,12 +466,19 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { var env = Environment.current + // FIXME: This is largely a workaround for improper rpath setup on Linux. It should be + // removed once the Swift Build backend switches to use swiftc as the linker driver + // for targets with Swift sources. For now, limit the scope to non-macOS, so that + // plugins do not inadvertently use the toolchain stdlib instead of the OS stdlib + // when built with a Swift.org toolchain. + #if !os(macOS) // Update the environment for any runtime library paths that tools compiled // for the command plugin might require after they have been built. let runtimeLibPaths = self.toolchain.runtimeLibraryPaths for libPath in runtimeLibPaths { env.appendPath(key: .libraryPath, value: libPath.pathString) } + #endif #if os(Windows) let pluginLibraryPath = self.toolchain.swiftPMLibrariesLocation.pluginLibraryPath.pathString diff --git a/Sources/SwiftBuildSupport/PIFBuilder.swift b/Sources/SwiftBuildSupport/PIFBuilder.swift index 24bc550218b..42dbd653da8 100644 --- a/Sources/SwiftBuildSupport/PIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PIFBuilder.swift @@ -333,12 +333,19 @@ public final class PIFBuilder { buildCommands.append(contentsOf: result.buildCommands.map( { buildCommand in var newEnv: Environment = buildCommand.configuration.environment + // FIXME: This is largely a workaround for improper rpath setup on Linux. It should be + // removed once the Swift Build backend switches to use swiftc as the linker driver + // for targets with Swift sources. For now, limit the scope to non-macOS, so that + // plugins do not inadvertently use the toolchain stdlib instead of the OS stdlib + // when built with a Swift.org toolchain. + #if !os(macOS) let runtimeLibPaths = buildParameters.toolchain.runtimeLibraryPaths // Add paths to swift standard runtime libraries to the library path so that they can be found at runtime for libPath in runtimeLibPaths { newEnv.appendPath(key: .libraryPath, value: libPath.pathString) } + #endif // Append the system path at the end so that necessary system tool paths can be found if let pathValue = Environment.current[EnvironmentKey.path] { diff --git a/Sources/SwiftSDKCommand/ConfigureSwiftSDK.swift b/Sources/SwiftSDKCommand/ConfigureSwiftSDK.swift index 1c6f9512e93..7000b52b166 100644 --- a/Sources/SwiftSDKCommand/ConfigureSwiftSDK.swift +++ b/Sources/SwiftSDKCommand/ConfigureSwiftSDK.swift @@ -117,7 +117,7 @@ struct ConfigureSwiftSDK: AsyncParsableCommand { let swiftSDKsDirectory = try self.getOrCreateSwiftSDKsDirectory() let hostToolchain = try UserToolchain(swiftSDK: SwiftSDK.hostSwiftSDK()) - let triple = try Triple.getHostTriple(usingSwiftCompiler: hostToolchain.swiftCompilerPath) + let triple = try Triple.getVersionedHostTriple(usingSwiftCompiler: hostToolchain.swiftCompilerPath) var commandError: Error? = nil do { diff --git a/Sources/SwiftSDKCommand/SwiftSDKSubcommand.swift b/Sources/SwiftSDKCommand/SwiftSDKSubcommand.swift index c1a62ad35a8..00ee520cc06 100644 --- a/Sources/SwiftSDKCommand/SwiftSDKSubcommand.swift +++ b/Sources/SwiftSDKCommand/SwiftSDKSubcommand.swift @@ -68,7 +68,7 @@ extension SwiftSDKSubcommand { ), environment: environment ) - let triple = try Triple.getHostTriple(usingSwiftCompiler: hostToolchain.swiftCompilerPath) + let triple = try Triple.getVersionedHostTriple(usingSwiftCompiler: hostToolchain.swiftCompilerPath) var commandError: Error? = nil do { diff --git a/Tests/CommandsTests/BuildCommandTests.swift b/Tests/CommandsTests/BuildCommandTests.swift index 1ee9ed8c50d..1a5adcd384c 100644 --- a/Tests/CommandsTests/BuildCommandTests.swift +++ b/Tests/CommandsTests/BuildCommandTests.swift @@ -1440,6 +1440,69 @@ struct BuildCommandTestCases { } } } + + @Test(.requireHostOS(.macOS), arguments: SupportedBuildSystemOnPlatform) + func buildingPackageWhichRequiresOlderDeploymentTarget(buildSystem: BuildSystemProvider.Kind) async throws { + // This fixture specifies a deployment target of macOS 12, and uses API obsoleted in macOS 13. The goal + // of this test is to ensure that SwiftPM respects the deployment target specified in the package manifest + // when passed no triple of an unversioned triple, rather than using the latests deployment target. + + // No triple - build should pass + try await fixture(name: "Miscellaneous/RequiresOlderDeploymentTarget") { path in + try await executeSwiftBuild( + path, + buildSystem: buildSystem, + throwIfCommandFails: true + ) + } + + let hostArch: String + #if arch(arm64) + hostArch = "arm64" + #elseif arch(x86_64) + hostArch = "x86_64" + #else + Issue.record("test is not supported on host arch") + return + #endif + + // Unversioned triple - build should pass + try await fixture(name: "Miscellaneous/RequiresOlderDeploymentTarget") { path in + try await executeSwiftBuild( + path, + extraArgs: ["--triple", "\(hostArch)-apple-macosx"], + buildSystem: buildSystem, + throwIfCommandFails: true + ) + } + + // Versioned triple with supported deployment target - build should pass + try await fixture(name: "Miscellaneous/RequiresOlderDeploymentTarget") { path in + try await executeSwiftBuild( + path, + extraArgs: ["--triple", "\(hostArch)-apple-macosx12.0"], + buildSystem: buildSystem, + throwIfCommandFails: true + ) + } + + // Versioned triple with unsupported deployment target - build should fail + try await withKnownIssue { + _ = try await fixture(name: "Miscellaneous/RequiresOlderDeploymentTarget") { path in + await #expect(throws: Error.self) { + try await executeSwiftBuild( + path, + extraArgs: ["--triple", "\(hostArch)-apple-macosx14.0"], + buildSystem: buildSystem, + throwIfCommandFails: true + ) + } + } + } when: { + // The native build system does not correctly pass the elevated deployment target + buildSystem != .swiftbuild + } + } } extension Triple {