Skip to content

Commit fde9916

Browse files
authored
Only automatically link snippets to product libraries (#5929)
Snippets illustrate how to use a package's products by design, so they shouldn't link to library targets that aren't exported as products. If snippets link to all library targets, one negative result would be inadvertently linking to test support libraries, which could cause failures due to automatic linking of `@rpath/libXCTestSwiftSupport.dylib`, a library not available to snippets at runtime. rdar://102746374
1 parent 1d23aab commit fde9916

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,9 @@ public final class PackageBuilder {
543543
if self.manifest.packageKind.isRoot {
544544
// Snippets: depend on all available library targets in the package.
545545
// TODO: Do we need to filter out targets that aren't available on the host platform?
546+
let productTargets = Set(manifest.products.flatMap { $0.targets })
546547
let snippetDependencies = targets
547-
.filter { $0.type == .library }
548+
.filter { $0.type == .library && productTargets.contains($0.name) }
548549
.map { Target.Dependency.target($0, conditions: []) }
549550
snippetTargets = try createSnippetTargets(dependencies: snippetDependencies)
550551
} else {

Tests/PackageLoadingTests/PackageBuilderTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,6 +2281,46 @@ class PackageBuilderTests: XCTestCase {
22812281
}
22822282
}
22832283
}
2284+
2285+
func testSnippetsLinkProductLibraries() throws {
2286+
let root = AbsolutePath(path: "/Foo")
2287+
let internalSourcesDir = root.appending(components: "Sources", "Internal")
2288+
let productSourcesDir = root.appending(components: "Sources", "Product")
2289+
let snippetsDir = root.appending(components: "Snippets")
2290+
let fs = InMemoryFileSystem(emptyFiles:
2291+
internalSourcesDir.appending(component: "Internal.swift").pathString,
2292+
productSourcesDir.appending(component: "Product.swift").pathString,
2293+
snippetsDir.appending(component: "ASnippet.swift").pathString)
2294+
2295+
let manifest = Manifest.createRootManifest(
2296+
name: "Foo", toolsVersion: .v5_7,
2297+
products: [
2298+
try ProductDescription(name: "Product", type: .library(.automatic), targets: ["Product"])
2299+
],
2300+
targets: [
2301+
try TargetDescription(name: "Internal"),
2302+
try TargetDescription(name: "Product"),
2303+
])
2304+
2305+
PackageBuilderTester(manifest, path: root, in: fs) { result, diagnostics in
2306+
result.checkProduct("Product") { product in
2307+
product.check(type: .library(.automatic), targets: ["Product"])
2308+
}
2309+
result.checkProduct("ASnippet") { aSnippet in
2310+
aSnippet.check(type: .snippet, targets: ["ASnippet"])
2311+
}
2312+
result.checkModule("Internal") { foo in
2313+
foo.checkSources(sources: ["Internal.swift"])
2314+
}
2315+
result.checkModule("Product") { foo in
2316+
foo.checkSources(sources: ["Product.swift"])
2317+
}
2318+
result.checkModule("ASnippet") { aSnippet in
2319+
aSnippet.checkSources(sources: ["ASnippet.swift"])
2320+
aSnippet.check(targetDependencies: ["Product"])
2321+
}
2322+
}
2323+
}
22842324
}
22852325

22862326
final class PackageBuilderTester {

0 commit comments

Comments
 (0)