From a6e5bc0b8f12d32a0fad66b73547f1babc59da25 Mon Sep 17 00:00:00 2001 From: Bassam Khouri Date: Fri, 21 Nov 2025 12:50:10 -0500 Subject: [PATCH] Statically linking Swift Stdlib in SwiftBuild if set Set the `SWIFT_FORCE_STATIC_LINK_STDLIB` build setting in SwiftBuild accordingly to the command line argument and if it's not on Darwin. In addition, set the SWIFT_RESOURCE_DIR setting as that is what the Native build system does. Fixes: #9320 Issue: rdar://163948614 --- .../Diagnostics+Extensions.swift | 26 ++++++ .../SwiftBuildSupport/SwiftBuildSystem.swift | 21 ++++- .../SwiftTesting+Tags.swift | 1 + .../SwiftBuildSystemTests.swift | 81 +++++++++++++++++++ 4 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 Sources/SwiftBuildSupport/Diagnostics+Extensions.swift diff --git a/Sources/SwiftBuildSupport/Diagnostics+Extensions.swift b/Sources/SwiftBuildSupport/Diagnostics+Extensions.swift new file mode 100644 index 00000000000..06d112ae5d5 --- /dev/null +++ b/Sources/SwiftBuildSupport/Diagnostics+Extensions.swift @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Basics + +extension Basics.Diagnostic { + package static var swiftBackDeployWarning: Self { + .warning( + """ + Swift compiler no longer supports statically linking the Swift libraries. They're included in the OS by \ + default starting with macOS Mojave 10.14.4 beta 3. For macOS Mojave 10.14.3 and earlier, there's an \ + optional "Swift 5 Runtime Support for Command Line Tools" package that can be downloaded from \"More Downloads\" \ + for Apple Developers at https://developer.apple.com/download/more/ + """ + ) + } +} diff --git a/Sources/SwiftBuildSupport/SwiftBuildSystem.swift b/Sources/SwiftBuildSupport/SwiftBuildSystem.swift index 9e10380367d..81ac45ddf6a 100644 --- a/Sources/SwiftBuildSupport/SwiftBuildSystem.swift +++ b/Sources/SwiftBuildSupport/SwiftBuildSystem.swift @@ -1055,7 +1055,7 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { } try settings.merge(Self.constructDebuggingSettingsOverrides(from: buildParameters.debuggingParameters), uniquingKeysWith: reportConflict) try settings.merge(Self.constructDriverSettingsOverrides(from: buildParameters.driverParameters), uniquingKeysWith: reportConflict) - try settings.merge(Self.constructLinkerSettingsOverrides(from: buildParameters.linkingParameters), uniquingKeysWith: reportConflict) + try settings.merge(self.constructLinkerSettingsOverrides(from: buildParameters.linkingParameters, triple: buildParameters.triple), uniquingKeysWith: reportConflict) try settings.merge(Self.constructTestingSettingsOverrides(from: buildParameters.testingParameters), uniquingKeysWith: reportConflict) try settings.merge(Self.constructAPIDigesterSettingsOverrides(from: buildParameters.apiDigesterMode), uniquingKeysWith: reportConflict) @@ -1142,7 +1142,10 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { return settings } - private static func constructLinkerSettingsOverrides(from parameters: BuildParameters.Linking) -> [String: String] { + private func constructLinkerSettingsOverrides( + from parameters: BuildParameters.Linking, + triple: Triple, + ) -> [String: String] { var settings: [String: String] = [:] if parameters.linkerDeadStrip { @@ -1160,7 +1163,19 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { break } - // TODO: shouldLinkStaticSwiftStdlib + if triple.isDarwin() && parameters.shouldLinkStaticSwiftStdlib { + self.observabilityScope.emit(.swiftBackDeployWarning) + } else { + if parameters.shouldLinkStaticSwiftStdlib { + settings["SWIFT_FORCE_STATIC_LINK_STDLIB"] = "YES" + } else { + settings["SWIFT_FORCE_STATIC_LINK_STDLIB"] = "NO" + } + } + + if let resourcesPath = self.buildParameters.toolchain.swiftResourcesPath(isStatic: parameters.shouldLinkStaticSwiftStdlib) { + settings["SWIFT_RESOURCE_DIR"] = resourcesPath.pathString + } return settings } diff --git a/Sources/_InternalTestSupport/SwiftTesting+Tags.swift b/Sources/_InternalTestSupport/SwiftTesting+Tags.swift index 66d6c441ccc..1801424cfbd 100644 --- a/Sources/_InternalTestSupport/SwiftTesting+Tags.swift +++ b/Sources/_InternalTestSupport/SwiftTesting+Tags.swift @@ -34,6 +34,7 @@ extension Tag.FunctionalArea { @Tag public static var PIF: Tag @Tag public static var IndexMode: Tag @Tag public static var Sanitizer: Tag + @Tag public static var LinkSwiftStaticStdlib: Tag } extension Tag.Feature { diff --git a/Tests/SwiftBuildSupportTests/SwiftBuildSystemTests.swift b/Tests/SwiftBuildSupportTests/SwiftBuildSystemTests.swift index f8a6c243bde..9ff233a7cff 100644 --- a/Tests/SwiftBuildSupportTests/SwiftBuildSystemTests.swift +++ b/Tests/SwiftBuildSupportTests/SwiftBuildSystemTests.swift @@ -197,6 +197,87 @@ struct SwiftBuildSystemTests { } } + @Suite( + .tags( + .FunctionalArea.LinkSwiftStaticStdlib, + ), + ) + struct SwiftStaticStdlibSettingTests { + @Test + func makingBuildParametersRaisesAWarningWhenRunOnDarwin() async throws { + // GIVEN we have a Darwin triple + let triple = try Triple("x86_64-apple-macosx") + // AND we want to statically link Swift sdtlib + let shouldLinkStaticSwiftStdlib = true + try await withInstantiatedSwiftBuildSystem( + fromFixture: "PIFBuilder/Simple", + buildParameters: mockBuildParameters( + destination: .host, + shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, + triple: triple, + ), + ) { swiftBuild, session, observabilityScope, buildParameters in + // WHEN we make the build parameter + let _: SWBBuildParameters = try await swiftBuild.makeBuildParameters( + session: session, + symbolGraphOptions: nil, + setToolchainSetting: false, // Set this to false as SwiftBuild checks the toolchain path + ) + + // THEN we expect a warning to be emitted + let warnings = observabilityScope.diagnostics.filter { + $0.severity == .warning + } + #expect(warnings.count == 1) + + let diagnostic = try #require(warnings.first) + // AND we expect the diagnostic message, severity and description to be as expected + #expect(diagnostic.message == Basics.Diagnostic.swiftBackDeployWarning.message) + #expect(diagnostic.severity == Basics.Diagnostic.swiftBackDeployWarning.severity) + #expect(diagnostic.description == Basics.Diagnostic.swiftBackDeployWarning.description) + } + } + + @Test( + arguments: [ + (shouldLinkStaticSwiftStdlib: true, expectedValue: "YES"), + (shouldLinkStaticSwiftStdlib: false, expectedValue: "NO"), + ] + ) + func swiftStaticStdLibSettingIsSetCorrectly( + shouldLinkStaticSwiftStdlib: Bool, + expectedValue: String + ) async throws { + // GIVEN we have a non-darwin triple AND we want statically link Swift sdtlib or not + let nonDarwinTriple = try Triple("i686-pc-windows-cygnus") + try await withInstantiatedSwiftBuildSystem( + fromFixture: "PIFBuilder/Simple", + buildParameters: mockBuildParameters( + destination: .host, + shouldLinkStaticSwiftStdlib: shouldLinkStaticSwiftStdlib, + triple: nonDarwinTriple, + ), + ) { swiftBuild, session, observabilityScope, buildParameters in + // WHEN we make the build parameter + let buildSettings = try await swiftBuild.makeBuildParameters( + session: session, + symbolGraphOptions: nil, + setToolchainSetting: false, // Set this to false as SwiftBuild checks the toolchain path + ) + + // THEN we don't expect any warnings to be emitted + let warnings = observabilityScope.diagnostics.filter { + $0.severity == .warning + } + #expect(warnings.isEmpty) + + // AND we expect the build setting to be set correctly + let synthesizedArgs = try #require(buildSettings.overrides.synthesized) + #expect(synthesizedArgs.table["SWIFT_FORCE_STATIC_LINK_STDLIB"] == expectedValue) + } + } + } + @Test( arguments: BuildParameters.IndexStoreMode.allCases, // arguments: [BuildParameters.IndexStoreMode.on],