Skip to content

Commit 76e3594

Browse files
authored
Swift SDKs: implement swiftResourcesPath (#6717)
Implements `swiftResourcesPath` and `swiftStaticResourcesPath` from the `swift-sdk.json` spec. ### Motivation: SwiftPM previously knew how to parse these fields from the SDK manifest, but didn't actually do anything with them. ### Modifications: - Pass `-resource-dir` to swiftc for compile jobs - Pass `-resource-dir` to both swiftc and clang for link jobs ### Result: Toolchains that override `swiftResourcesPath` and/or `swiftStaticResourcesPath` should now behave as expected.
1 parent ab95810 commit 76e3594

File tree

6 files changed

+84
-8
lines changed

6 files changed

+84
-8
lines changed

Sources/Build/BuildDescription/ProductBuildDescription.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
187187
derivedProductType = self.product.type
188188
}
189189

190+
var isLinkingStaticStdlib = false
190191
switch derivedProductType {
191192
case .macro:
192193
throw InternalError("macro not supported") // should never be reached
@@ -213,11 +214,13 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
213214
args += self.deadStripArguments
214215
case .executable, .snippet:
215216
// Link the Swift stdlib statically, if requested.
217+
// TODO: unify this logic with SwiftTargetBuildDescription.stdlibArguments
216218
if self.buildParameters.shouldLinkStaticSwiftStdlib {
217219
if self.buildParameters.targetTriple.isDarwin() {
218220
self.observabilityScope.emit(.swiftBackDeployError)
219221
} else if self.buildParameters.targetTriple.isSupportingStaticStdlib {
220222
args += ["-static-stdlib"]
223+
isLinkingStaticStdlib = true
221224
}
222225
}
223226
args += ["-emit-executable"]
@@ -243,6 +246,16 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
243246
throw InternalError("unexpectedly asked to generate linker arguments for a plugin product")
244247
}
245248

249+
if let resourcesPath = self.buildParameters.toolchain.swiftResourcesPath(isStatic: isLinkingStaticStdlib) {
250+
args += ["-resource-dir", "\(resourcesPath)"]
251+
}
252+
253+
// clang resources are always in lib/swift/
254+
if let dynamicResourcesPath = self.buildParameters.toolchain.swiftResourcesPath {
255+
let clangResourcesPath = dynamicResourcesPath.appending("clang")
256+
args += ["-Xclang-linker", "-resource-dir", "-Xclang-linker", "\(clangResourcesPath)"]
257+
}
258+
246259
// Set rpath such that dynamic libraries are looked up
247260
// adjacent to the product.
248261
if self.buildParameters.targetTriple.isLinux() {

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,12 +1283,18 @@ public final class SwiftTargetBuildDescription {
12831283
}
12841284

12851285
private var stdlibArguments: [String] {
1286-
if self.buildParameters.shouldLinkStaticSwiftStdlib,
1287-
self.buildParameters.targetTriple.isSupportingStaticStdlib
1288-
{
1289-
return ["-static-stdlib"]
1290-
} else {
1291-
return []
1286+
var arguments: [String] = []
1287+
1288+
let isLinkingStaticStdlib = self.buildParameters.shouldLinkStaticSwiftStdlib
1289+
&& self.buildParameters.targetTriple.isSupportingStaticStdlib
1290+
if isLinkingStaticStdlib {
1291+
arguments += ["-static-stdlib"]
12921292
}
1293+
1294+
if let resourcesPath = self.buildParameters.toolchain.swiftResourcesPath(isStatic: isLinkingStaticStdlib) {
1295+
arguments += ["-resource-dir", "\(resourcesPath)"]
1296+
}
1297+
1298+
return arguments
12931299
}
12941300
}

Sources/PackageModel/Toolchain.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ public protocol Toolchain {
1919
/// Path of the `swiftc` compiler.
2020
var swiftCompilerPath: AbsolutePath { get }
2121

22+
/// Path to `lib/swift`
23+
var swiftResourcesPath: AbsolutePath? { get }
24+
25+
/// Path to `lib/swift_static`
26+
var swiftStaticResourcesPath: AbsolutePath? { get }
27+
2228
/// Whether the used compiler is from a open source development toolchain.
2329
var isSwiftDevelopmentToolchain: Bool { get }
2430

@@ -81,7 +87,15 @@ extension Toolchain {
8187
return try AbsolutePath(validating: "../../lib", relativeTo: resolveSymlinks(swiftCompilerPath))
8288
}
8389
}
84-
90+
91+
/// Returns the appropriate Swift resources directory path.
92+
///
93+
/// - Parameter static: Controls whether to use the static or dynamic
94+
/// resources directory.
95+
public func swiftResourcesPath(isStatic: Bool) -> AbsolutePath? {
96+
isStatic ? swiftStaticResourcesPath : swiftResourcesPath
97+
}
98+
8599
public var extraCCFlags: [String] {
86100
extraFlags.cCompilerFlags
87101
}

Sources/PackageModel/UserToolchain.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ public final class UserToolchain: Toolchain {
4040
/// An array of paths to search for libraries at link time.
4141
public let librarySearchPaths: [AbsolutePath]
4242

43+
/// Path containing Swift resources for dynamic linking.
44+
public var swiftResourcesPath: AbsolutePath? {
45+
destination.pathsConfiguration.swiftResourcesPath
46+
}
47+
48+
/// Path containing Swift resources for static linking.
49+
public var swiftStaticResourcesPath: AbsolutePath? {
50+
destination.pathsConfiguration.swiftStaticResourcesPath
51+
}
52+
4353
/// Additional flags to be passed to the build tools.
4454
public var extraFlags: BuildFlags
4555

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3569,6 +3569,9 @@ final class BuildPlanTests: XCTestCase {
35693569
Manifest.createRootManifest(
35703570
displayName: "Pkg",
35713571
path: "/Pkg",
3572+
products: [
3573+
ProductDescription(name: "exe", type: .executable, targets: ["exe"]),
3574+
],
35723575
targets: [
35733576
TargetDescription(name: "exe", dependencies: ["lib"]),
35743577
TargetDescription(name: "lib", dependencies: []),
@@ -3586,7 +3589,11 @@ final class BuildPlanTests: XCTestCase {
35863589
],
35873590
rootPaths: try UserToolchain.default.swiftSDK.toolset.rootPaths
35883591
),
3589-
pathsConfiguration: .init(sdkRootPath: "/fake/sdk")
3592+
pathsConfiguration: .init(
3593+
sdkRootPath: "/fake/sdk",
3594+
swiftResourcesPath: "/fake/lib/swift",
3595+
swiftStaticResourcesPath: "/fake/lib/swift_static"
3596+
)
35903597
)
35913598
let mockToolchain = try UserToolchain(swiftSDK: userSwiftSDK)
35923599
let extraBuildParameters = mockBuildParameters(toolchain: mockToolchain,
@@ -3615,6 +3622,7 @@ final class BuildPlanTests: XCTestCase {
36153622
let exe = try result.target(for: "exe").swiftTarget().compileArguments()
36163623
XCTAssertMatch(exe, [
36173624
"-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))",
3625+
"-resource-dir", "/fake/lib/swift",
36183626
.anySequence,
36193627
"-swift-flag-from-json",
36203628
.anySequence,
@@ -3624,6 +3632,29 @@ final class BuildPlanTests: XCTestCase {
36243632
.anySequence,
36253633
"-Xcc", "-clang-command-line-flag"
36263634
])
3635+
3636+
let exeProduct = try result.buildProduct(for: "exe").linkArguments()
3637+
XCTAssertMatch(exeProduct, [.anySequence, "-resource-dir", "/fake/lib/swift", "-Xclang-linker", "-resource-dir", "-Xclang-linker", "/fake/lib/swift/clang", .anySequence])
3638+
3639+
let staticBuildParameters = {
3640+
var copy = extraBuildParameters
3641+
copy.shouldLinkStaticSwiftStdlib = true
3642+
// pick a triple with support for static linking
3643+
copy.targetTriple = .x86_64Linux
3644+
return copy
3645+
}()
3646+
let staticResult = try BuildPlanResult(plan: BuildPlan(
3647+
buildParameters: staticBuildParameters,
3648+
graph: graph,
3649+
fileSystem: fs,
3650+
observabilityScope: observability.topScope
3651+
))
3652+
3653+
let staticExe = try staticResult.target(for: "exe").swiftTarget().compileArguments()
3654+
XCTAssertMatch(staticExe, [.anySequence, "-resource-dir", "/fake/lib/swift_static", .anySequence])
3655+
3656+
let staticExeProduct = try staticResult.buildProduct(for: "exe").linkArguments()
3657+
XCTAssertMatch(staticExeProduct, [.anySequence, "-resource-dir", "/fake/lib/swift_static", "-Xclang-linker", "-resource-dir", "-Xclang-linker", "/fake/lib/swift/clang", .anySequence])
36273658
}
36283659

36293660
func testUserToolchainWithToolsetCompileFlags() throws {

Tests/BuildTests/MockBuildTestHelper.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct MockToolchain: PackageModel.Toolchain {
2828
let swiftCompilerPath = AbsolutePath("/fake/path/to/swiftc")
2929
let includeSearchPaths = [AbsolutePath]()
3030
let librarySearchPaths = [AbsolutePath]()
31+
let swiftResourcesPath: AbsolutePath? = nil
32+
let swiftStaticResourcesPath: AbsolutePath? = nil
3133
let isSwiftDevelopmentToolchain = false
3234
let swiftPluginServerPath: AbsolutePath? = nil
3335
let extraFlags = PackageModel.BuildFlags()

0 commit comments

Comments
 (0)