Skip to content

Commit cb71bd7

Browse files
committed
Allow build & run to reference unreachable targets
1 parent 1644036 commit cb71bd7

File tree

15 files changed

+238
-43
lines changed

15 files changed

+238
-43
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// swift-tools-version:4.0
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "A",
6+
products: [
7+
.executable(name: "aexec", targets: ["ATarget"])
8+
],
9+
dependencies: [
10+
.package(url: "../B", from: "1.0.0"),
11+
.package(url: "../C", from: "1.0.0")
12+
],
13+
targets: [
14+
.target(name: "ATarget", dependencies: [
15+
.product(name: "BLibrary")
16+
])
17+
])
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import BTarget1
2+
3+
BTarget1()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// swift-tools-version:4.0
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "B",
6+
products: [
7+
.library(name: "BLibrary", targets: ["BTarget1"]),
8+
.executable(name: "bexec", targets: ["BTarget2"])
9+
],
10+
targets: [
11+
.target(name: "BTarget1", dependencies: []),
12+
.target(name: "BTarget2", dependencies: [])
13+
])
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public struct BTarget1 {
2+
public init() {}
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print("BTarget2")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// swift-tools-version:4.0
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "C",
6+
products: [
7+
.executable(name: "cexec", targets: ["CTarget"])
8+
],
9+
targets: [
10+
.target(name: "CTarget", dependencies: [])
11+
])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print("CTarget")

Sources/Build/BuildPlan.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ public class BuildPlan {
474474

475475
// Create build target description for each target which we need to plan.
476476
var targetMap = [ResolvedTarget: TargetDescription]()
477-
for target in graph.targets {
477+
for target in graph.allTargets {
478478
switch target.underlyingTarget {
479479
case is SwiftTarget:
480480
targetMap[target] = .swift(SwiftTargetDescription(target: target, buildParameters: buildParameters))
@@ -511,7 +511,7 @@ public class BuildPlan {
511511
var productMap: [ResolvedProduct: ProductBuildDescription] = [:]
512512
// Create product description for each product we have in the package graph except
513513
// for automatic libraries because they don't produce any output.
514-
for product in graph.products where product.type != .library(.automatic) {
514+
for product in graph.allProducts where product.type != .library(.automatic) {
515515
productMap[product] = ProductBuildDescription(
516516
product: product, buildParameters: buildParameters)
517517
}

Sources/Build/llbuild.swift

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public struct LLBuildManifestGenerator {
5151
private var otherTargets: [Target] = []
5252

5353
/// Append a command.
54-
mutating func append(_ target: Target, isTest: Bool) {
54+
mutating func append(_ target: Target, buildByDefault: Bool, isTest: Bool) {
5555
// Create a phony command with a virtual output node that represents the target.
5656
let virtualNodeName = "<\(target.name)>"
5757
let phonyTool = PhonyTool(inputs: target.outputs, outputs: [virtualNodeName])
@@ -63,14 +63,17 @@ public struct LLBuildManifestGenerator {
6363
newTarget.cmds.insert(phonyCommand)
6464
otherTargets.append(newTarget)
6565

66-
if !isTest {
67-
main.outputs += newTarget.outputs
68-
main.cmds += newTarget.cmds
66+
if buildByDefault {
67+
if !isTest {
68+
main.outputs += newTarget.outputs
69+
main.cmds += newTarget.cmds
70+
}
71+
72+
// Always build everything for the test target.
73+
test.outputs += newTarget.outputs
74+
test.cmds += newTarget.cmds
6975
}
7076

71-
// Always build everything for the test target.
72-
test.outputs += newTarget.outputs
73-
test.cmds += newTarget.cmds
7477
allCommands += newTarget.cmds
7578
}
7679
}
@@ -80,18 +83,26 @@ public struct LLBuildManifestGenerator {
8083
var targets = Targets()
8184

8285
// Create commands for all target description in the plan.
83-
for buildTarget in plan.targets {
84-
switch buildTarget {
85-
case .swift(let target):
86-
targets.append(createSwiftCompileTarget(target), isTest: target.isTestTarget)
87-
case .clang(let target):
88-
targets.append(createClangCompileTarget(target), isTest: target.isTestTarget)
86+
for (target, description) in plan.targetMap {
87+
switch description {
88+
case .swift(let description):
89+
// Only build targets by default if they are reachabe from a root target.
90+
targets.append(createSwiftCompileTarget(description),
91+
buildByDefault: plan.graph.targets.contains(target),
92+
isTest: description.isTestTarget)
93+
case .clang(let description):
94+
targets.append(createClangCompileTarget(description),
95+
buildByDefault: plan.graph.targets.contains(target),
96+
isTest: description.isTestTarget)
8997
}
9098
}
9199

92100
// Create command for all products in the plan.
93-
for buildProduct in plan.buildProducts {
94-
targets.append(createProductTarget(buildProduct), isTest: buildProduct.product.type == .test)
101+
for (product, description) in plan.productMap {
102+
// Only build products by default if they are reachabe from a root target.
103+
targets.append(createProductTarget(description),
104+
buildByDefault: plan.graph.products.contains(product),
105+
isTest: product.type == .test)
95106
}
96107

97108
// Write the manifest.

Sources/Commands/SwiftRunTool.swift

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,27 +126,30 @@ public class SwiftRunTool: SwiftTool<RunToolOptions> {
126126

127127
/// Returns the path to the correct executable based on options.
128128
private func findProduct(in plan: BuildPlan) throws -> ResolvedProduct {
129-
let executableProducts = plan.graph.products.filter({ $0.type == .executable })
130-
131-
// Error out if the product contains no executable.
132-
guard executableProducts.count > 0 else {
133-
throw RunError.noExecutableFound
134-
}
135-
136129
if let executable = options.executable {
137-
// If the exectuable is explicitly specified, verify that it exists.
138-
guard let executableProduct = executableProducts.first(where: { $0.name == executable }) else {
130+
// If the exectuable is explicitly specified, search through all products.
131+
guard let executableProduct = plan.graph.allProducts.first(where: {
132+
$0.type == .executable && $0.name == executable
133+
}) else {
139134
throw RunError.executableNotFound(executable)
140135
}
141136

142137
return executableProduct
143138
} else {
139+
// If the executably is implicit, search through root products.
140+
let rootExecutables = plan.graph.rootPackages.flatMap({ $0.products }).filter({ $0.type == .executable })
141+
142+
// Error out if the package contains no executables.
143+
guard rootExecutables.count > 0 else {
144+
throw RunError.noExecutableFound
145+
}
146+
144147
// Only implicitly deduce the executable if it is the only one.
145-
guard executableProducts.count == 1 else {
146-
throw RunError.multipleExecutables(executableProducts.map({ $0.name }))
148+
guard rootExecutables.count == 1 else {
149+
throw RunError.multipleExecutables(rootExecutables.map({ $0.name }))
147150
}
148151

149-
return executableProducts[0]
152+
return rootExecutables[0]
150153
}
151154
}
152155

0 commit comments

Comments
 (0)