Skip to content

Commit 7918e4d

Browse files
authored
Merge pull request swiftlang#1381 from hartbit/build-unreachable-products-and-targets
Allow build & run to reference unreachable targets
2 parents 0a2ecf0 + 527a735 commit 7918e4d

File tree

19 files changed

+281
-71
lines changed

19 files changed

+281
-71
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import XCTest
2+
XCTMain([])
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: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ public class BuildPlan {
499499

500500
// Create build target description for each target which we need to plan.
501501
var targetMap = [ResolvedTarget: TargetDescription]()
502-
for target in graph.targets {
502+
for target in graph.allTargets {
503503
switch target.underlyingTarget {
504504
case is SwiftTarget:
505505
targetMap[target] = .swift(SwiftTargetDescription(target: target, buildParameters: buildParameters))
@@ -518,10 +518,7 @@ public class BuildPlan {
518518
if buildParameters.triple.isLinux() {
519519
// FIXME: Create a target for LinuxMain file on linux.
520520
// This will go away once it is possible to auto detect tests.
521-
let testProducts = graph.products.filter({ $0.type == .test })
522-
if testProducts.count > 1 {
523-
fatalError("It is not possible to have multiple test products on linux \(testProducts)")
524-
}
521+
let testProducts = graph.allProducts.filter({ $0.type == .test })
525522

526523
for product in testProducts {
527524
guard let linuxMainTarget = product.linuxMainTarget else {
@@ -536,7 +533,7 @@ public class BuildPlan {
536533
var productMap: [ResolvedProduct: ProductBuildDescription] = [:]
537534
// Create product description for each product we have in the package graph except
538535
// for automatic libraries because they don't produce any output.
539-
for product in graph.products where product.type != .library(.automatic) {
536+
for product in graph.allProducts where product.type != .library(.automatic) {
540537
productMap[product] = ProductBuildDescription(
541538
product: product, buildParameters: buildParameters)
542539
}

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.values, 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.reachableTargets.contains(target),
92+
isTest: description.isTestTarget)
93+
case .clang(let description):
94+
targets.append(createClangCompileTarget(description),
95+
buildByDefault: plan.graph.reachableTargets.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.reachableProducts.contains(product),
105+
isTest: product.type == .test)
95106
}
96107

97108
// Write the manifest.

0 commit comments

Comments
 (0)