Skip to content

Commit 601cd1a

Browse files
committed
Validation of package products should check that a library product doesn't try to include executable targets
Currently a library product that includes an executable target in its `targets` array only results in a warning. This was the best that could be done before `executableTarget` was introduced, since further checking was needed to see if a `target` was a library or executable target. Since we have explicit types now, we should promote this to an error since people are running into it and it's not clear what the problem is. This check is limited to tools version 5.7 or later. This change includes a new test fixture and unit test. rdar://95782540
1 parent fa91d29 commit 601cd1a

File tree

5 files changed

+39
-0
lines changed

5 files changed

+39
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// swift-tools-version: 5.7
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "PackageWithMalformedLibraryProduct",
6+
products: [
7+
.library(
8+
name: "PackageWithMalformedLibraryProduct",
9+
targets: ["PackageWithMalformedLibraryProduct"]),
10+
],
11+
targets: [
12+
.executableTarget(
13+
name: "PackageWithMalformedLibraryProduct")
14+
]
15+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print("Hello World")

Sources/PackageLoading/Diagnostics.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ extension Basics.Diagnostic {
5656
.error("system library product \(product) shouldn't have a type and contain only one target")
5757
}
5858

59+
static func libraryProductWithExectuableTarget(product: String) -> Self {
60+
.error("library product '\(product)' should not contain an executable target")
61+
}
62+
5963
static func nonPluginProductWithPluginTargets(product: String, type: ProductType, pluginTargets: [String]) -> Self {
6064
.error("\(type.description) product '\(product)' should not contain plugin targets (it has \(pluginTargets.map{ "'\($0)'" }.joined(separator: ", ")))")
6165
}

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,13 @@ public final class PackageBuilder {
12221222
self.observabilityScope.emit(.nonPluginProductWithPluginTargets(product: product.name, type: product.type, pluginTargets: pluginTargets.map{ $0.name }))
12231223
return false
12241224
}
1225+
if manifest.toolsVersion >= .v5_7 {
1226+
let executableTargets = targets.filter { $0.type == .executable }
1227+
guard executableTargets.isEmpty else {
1228+
self.observabilityScope.emit(.libraryProductWithExectuableTarget(product: product.name))
1229+
return false
1230+
}
1231+
}
12251232
return true
12261233
}
12271234

Tests/FunctionalTests/MiscellaneousTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,18 @@ class MiscellaneousTestCase: XCTestCase {
690690
}
691691
}
692692

693+
func testLibraryTriesToIncludeExecutableTarget() throws {
694+
try fixture(name: "Miscellaneous/PackageWithMalformedLibraryProduct") { path in
695+
XCTAssertThrowsCommandExecutionError(try executeSwiftBuild(path)) { error in
696+
// if our code crashes we'll get an exit code of 256
697+
guard error.result.exitStatus == .terminated(code: 1) else {
698+
return XCTFail("failed in an unexpected manner: \(error)")
699+
}
700+
XCTAssertMatch(error.stdout + error.stderr, .contains("library product 'PackageWithMalformedLibraryProduct' should not contain an executable target"))
701+
}
702+
}
703+
}
704+
693705
func testEditModeEndToEnd() throws {
694706
try fixture(name: "Miscellaneous/Edit") { fixturePath in
695707
let prefix = resolveSymlinks(fixturePath)

0 commit comments

Comments
 (0)