Skip to content

Commit a9ddddb

Browse files
authored
Derive dynamic libraries explicitly to avoid linker errors for "release" builds (#7284)
Derive dynamic libraries explicitly to avoid linker errors for "release" builds. rdar://108561857 ### Motivation: One of the test fixtures in XPM that we've been using since 2019 succeeds in Debug builds but fails in Release builds with linker errors. The fix is to derive dynamic libraries for linking. ### Modifications: Derive dynamic libraries explicitly for linking. ### Result: Now release builds are also successful.
1 parent 9dccbd8 commit a9ddddb

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

Sources/Build/BuildPlan/BuildPlan+Product.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ extension BuildPlan {
143143
topLevelDependencies = []
144144
}
145145

146+
// get the dynamic libraries for explicitly linking rdar://108561857
147+
func recursiveDynamicLibraries(for product: ResolvedProduct) throws -> [ResolvedProduct] {
148+
let dylibs = try computeDependencies(of: product, buildParameters: buildParameters).dylibs
149+
return try dylibs + dylibs.flatMap { try recursiveDynamicLibraries(for: $0) }
150+
}
151+
146152
// Sort the product targets in topological order.
147153
let nodes: [ResolvedTarget.Dependency] = product.targets.map { .target($0, conditions: []) }
148154
let allTargets = try topologicalSort(nodes, successors: { dependency in
@@ -175,7 +181,9 @@ extension BuildPlan {
175181
return productDependencies
176182
case .plugin:
177183
return shouldExcludePlugins ? [] : productDependencies
178-
case .library(.dynamic), .test, .executable, .snippet, .macro:
184+
case .library(.dynamic):
185+
return try recursiveDynamicLibraries(for: product).map { .product($0, conditions: []) }
186+
case .test, .executable, .snippet, .macro:
179187
return []
180188
}
181189
}

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6198,4 +6198,76 @@ final class BuildPlanTests: XCTestCase {
61986198
XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), linkArguments)
61996199
XCTAssertNoDiagnostics(observability.diagnostics)
62006200
}
6201+
6202+
// testing of deriving dynamic libraries for explicitly linking rdar://108561857
6203+
func testDerivingDylibs() throws {
6204+
let fs = InMemoryFileSystem(
6205+
emptyFiles:
6206+
"/thisPkg/Sources/exe/main.swift",
6207+
"/fooPkg/Sources/FooLogging/file.swift",
6208+
"/barPkg/Sources/BarLogging/file.swift"
6209+
)
6210+
let observability = ObservabilitySystem.makeForTesting()
6211+
let graph = try loadPackageGraph(
6212+
fileSystem: fs,
6213+
manifests: [
6214+
Manifest.createFileSystemManifest(
6215+
displayName: "fooPkg",
6216+
path: "/fooPkg",
6217+
dependencies: [
6218+
.localSourceControl(path: "/barPkg", requirement: .upToNextMajor(from: "1.0.0")),
6219+
],
6220+
products: [
6221+
ProductDescription(name: "FooLogging", type: .library(.dynamic), targets: ["FooLogging"]),
6222+
],
6223+
targets: [
6224+
TargetDescription(
6225+
name: "FooLogging",
6226+
dependencies: [.product(name: "BarLogging", package: "barPkg")]
6227+
),
6228+
]
6229+
),
6230+
Manifest.createFileSystemManifest(
6231+
displayName: "barPkg",
6232+
path: "/barPkg",
6233+
products: [
6234+
ProductDescription(name: "BarLogging", type: .library(.dynamic), targets: ["BarLogging"]),
6235+
],
6236+
targets: [
6237+
TargetDescription(name: "BarLogging", dependencies: []),
6238+
]
6239+
),
6240+
Manifest.createRootManifest(
6241+
displayName: "thisPkg",
6242+
path: "/thisPkg",
6243+
toolsVersion: .v5_8,
6244+
dependencies: [
6245+
.localSourceControl(path: "/fooPkg", requirement: .upToNextMajor(from: "1.0.0")),
6246+
],
6247+
targets: [
6248+
TargetDescription(
6249+
name: "exe",
6250+
dependencies: [.product(name: "FooLogging", package: "fooPkg"),],
6251+
type: .executable
6252+
),
6253+
]
6254+
),
6255+
],
6256+
observabilityScope: observability.topScope
6257+
)
6258+
XCTAssertNoDiagnostics(observability.diagnostics)
6259+
let result = try BuildPlanResult(plan: BuildPlan(
6260+
buildParameters: mockBuildParameters(shouldLinkStaticSwiftStdlib: true),
6261+
graph: graph,
6262+
fileSystem: fs,
6263+
observabilityScope: observability.topScope
6264+
))
6265+
result.checkProductsCount(3)
6266+
result.checkTargetsCount(3)
6267+
XCTAssertTrue(result.targetMap.values.contains { $0.target.name == "FooLogging" })
6268+
XCTAssertTrue(result.targetMap.values.contains { $0.target.name == "BarLogging" })
6269+
let buildProduct = try XCTUnwrap(result.productMap["exe"])
6270+
let dylibs = Array(buildProduct.dylibs.map({$0.product.name})).sorted()
6271+
XCTAssertEqual(dylibs, ["BarLogging", "FooLogging"])
6272+
}
62016273
}

0 commit comments

Comments
 (0)