Skip to content

Commit 0402ec1

Browse files
authored
[5.7] Validation of package products should check that a library product doesn't try to include executable targets (#5625) (#5629)
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 (cherry picked from commit 5bd3355)
1 parent 4f0577c commit 0402ec1

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 libraryProductWithExecutableTarget(product: String, executableTargets: [String]) -> Self {
60+
.error("library product '\(product)' should not contain executable targets (it has \(executableTargets.map{ "'\($0)'" }.joined(separator: ", ")))")
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(.libraryProductWithExecutableTarget(product: product.name, executableTargets: executableTargets.map{ $0.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
@@ -684,6 +684,18 @@ class MiscellaneousTestCase: XCTestCase {
684684
}
685685
}
686686

687+
func testLibraryTriesToIncludeExecutableTarget() throws {
688+
try fixture(name: "Miscellaneous/PackageWithMalformedLibraryProduct") { path in
689+
XCTAssertThrowsCommandExecutionError(try executeSwiftBuild(path)) { error in
690+
// if our code crashes we'll get an exit code of 256
691+
guard error.result.exitStatus == .terminated(code: 1) else {
692+
return XCTFail("failed in an unexpected manner: \(error)")
693+
}
694+
XCTAssertMatch(error.stdout + error.stderr, .contains("library product 'PackageWithMalformedLibraryProduct' should not contain executable targets (it has 'PackageWithMalformedLibraryProduct')"))
695+
}
696+
}
697+
}
698+
687699
func testEditModeEndToEnd() throws {
688700
try fixture(name: "Miscellaneous/Edit") { fixturePath in
689701
let prefix = resolveSymlinks(fixturePath)

0 commit comments

Comments
 (0)