Skip to content

Commit 301ee13

Browse files
committed
Cross compilation improvements
A collection of fixes and improvements related to cross-compilation. An attempt to make cross-compilation support more robust, consistent, error-prone and deal with performance regressions related to plugins. - `BuildParameters` are now associated with a destination (host or target) to make sure that they are always used in accordance with their original purpose. - `Buildset` gains a default `for:` parameter to indicate the intended destination of a product/target - LLBuild names for products and modules are computed based on the build parameters instead of relying on `buildTriple` of an product/target - Adds a way to get a command and llbuild name from a build description instead of having to reach for an underlying resolved module/product and pass parameters to it - Refactors most of the uses of `allTargets` and `allProducts` to use the graph and supply an intended destination - `SwiftTargetBuildDescription` no longer needs to reference `toolsBuildParameters` by reworking the way requires macros are referenced - Removes `ModulesGraph.updateBuildTripleRecursively` - Plugins: - Fixes a bug where graph doesn't get a "tools" product synthesized for an executable target referenced by a plugin - Fixes a bug where plugin outputs weren't added to test targets that a rebuilt for "tools" - Tests: - Introduces a new convenient way to mock build plans that respects tools/destination separation of parameters - Adds a "destination" parameter to `check{Target, Product}` default to `.destination` - `swift build` with `--target` and `--product` now behave consistently - performance regression related to plugins has been fixed - It should be harder to request product/target without a destination
1 parent a3541b8 commit 301ee13

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+997
-778
lines changed

Sources/Build/BuildDescription/PluginDescription.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public final class PluginDescription: Codable {
2929
/// the plugin).
3030
public let targetName: String
3131

32+
/// The language-level target name.
33+
public let targetC99Name: String
34+
3235
/// The names of any plugin products in that package that vend the plugin
3336
/// to other packages.
3437
public let productNames: [String]
@@ -56,6 +59,7 @@ public final class PluginDescription: Codable {
5659

5760
self.package = package.identity
5861
self.targetName = target.name
62+
self.targetC99Name = target.c99name
5963
self.productNames = products.map(\.name)
6064
self.toolsVersion = toolsVersion
6165
self.sources = target.sources

Sources/Build/BuildDescription/ResolvedModule+BuildDescription.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import SPMBuildCore
1717

1818
extension ResolvedModule {
1919
func tempsPath(_ buildParameters: BuildParameters) -> AbsolutePath {
20-
let suffix = buildParameters.suffix(triple: self.buildTriple)
20+
let suffix = buildParameters.suffix
2121
return buildParameters.buildPath.appending(component: "\(self.c99name)\(suffix).build")
2222
}
2323
}

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 58 additions & 63 deletions
Large diffs are not rendered by default.

Sources/Build/BuildDescription/TargetBuildDescription.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public enum TargetBuildDescription {
101101
var buildParameters: BuildParameters {
102102
switch self {
103103
case .swift(let swiftTargetBuildDescription):
104-
return swiftTargetBuildDescription.defaultBuildParameters
104+
return swiftTargetBuildDescription.buildParameters
105105
case .clang(let clangTargetBuildDescription):
106106
return clangTargetBuildDescription.buildParameters
107107
}

Sources/Build/BuildManifest/LLBuildManifestBuilder+Clang.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ extension LLBuildManifestBuilder {
9393
let additionalInputs = try addBuildToolPlugins(.clang(target))
9494

9595
// Create a phony node to represent the entire target.
96-
let targetName = target.target.getLLBuildTargetName(buildParameters: target.buildParameters)
96+
let targetName = target.llbuildTargetName
9797
let output: Node = .virtual(targetName)
9898

9999
self.manifest.addNode(output, toTarget: targetName)

Sources/Build/BuildManifest/LLBuildManifestBuilder+Product.swift

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import struct Basics.AbsolutePath
14+
import struct Basics.InternalError
1415
import struct LLBuildManifest.Node
16+
import struct SPMBuildCore.BuildParameters
17+
import struct PackageGraph.ResolvedProduct
1518

1619
extension LLBuildManifestBuilder {
1720
func createProductCommand(_ buildProduct: ProductBuildDescription) throws {
18-
let cmdName = try buildProduct.product.getCommandName(buildParameters: buildProduct.buildParameters)
21+
let cmdName = try buildProduct.commandName
1922

2023
// Add dependency on Info.plist generation on Darwin platforms.
2124
let testInputs: [AbsolutePath]
@@ -34,7 +37,7 @@ extension LLBuildManifestBuilder {
3437
}
3538

3639
// Create a phony node to represent the entire target.
37-
let targetName = try buildProduct.product.getLLBuildTargetName(buildParameters: buildProduct.buildParameters)
40+
let targetName = try buildProduct.llbuildTargetName
3841
let output: Node = .virtual(targetName)
3942

4043
let finalProductNode: Node
@@ -85,7 +88,7 @@ extension LLBuildManifestBuilder {
8588
outputPath: plistPath
8689
)
8790

88-
let cmdName = try buildProduct.product.getCommandName(buildParameters: buildProduct.buildParameters)
91+
let cmdName = try buildProduct.commandName
8992
let codeSigningOutput = Node.virtual(targetName + "-CodeSigning")
9093
try self.manifest.addShellCmd(
9194
name: "\(cmdName)-entitlements",
@@ -120,3 +123,48 @@ extension LLBuildManifestBuilder {
120123
)
121124
}
122125
}
126+
127+
extension ProductBuildDescription {
128+
package var llbuildTargetName: String {
129+
get throws {
130+
try self.product.getLLBuildTargetName(buildParameters: self.buildParameters)
131+
}
132+
}
133+
134+
package var commandName: String {
135+
get throws {
136+
try "C.\(self.llbuildTargetName)\(self.buildParameters.suffix)"
137+
}
138+
}
139+
}
140+
141+
extension ResolvedProduct {
142+
public func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String {
143+
let triple = buildParameters.triple.tripleString
144+
let config = buildParameters.buildConfig
145+
let suffix = buildParameters.suffix
146+
let potentialExecutableTargetName = "\(name)-\(triple)-\(config)\(suffix).exe"
147+
let potentialLibraryTargetName = "\(name)-\(triple)-\(config)\(suffix).dylib"
148+
149+
switch type {
150+
case .library(.dynamic):
151+
return potentialLibraryTargetName
152+
case .test:
153+
return "\(name)-\(triple)-\(config)\(suffix).test"
154+
case .library(.static):
155+
return "\(name)-\(triple)-\(config)\(suffix).a"
156+
case .library(.automatic):
157+
throw InternalError("automatic library not supported")
158+
case .executable, .snippet:
159+
return potentialExecutableTargetName
160+
case .macro:
161+
#if BUILD_MACROS_AS_DYLIBS
162+
return potentialLibraryTargetName
163+
#else
164+
return potentialExecutableTargetName
165+
#endif
166+
case .plugin:
167+
throw InternalError("unexpectedly asked for the llbuild target name of a plugin product")
168+
}
169+
}
170+
}

Sources/Build/BuildManifest/LLBuildManifestBuilder+Resources.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension LLBuildManifestBuilder {
4545
outputs.append(output)
4646
}
4747

48-
let cmdName = target.target.getLLBuildResourcesCmdName(buildParameters: target.buildParameters)
48+
let cmdName = target.llbuildResourcesCmdName
4949
self.manifest.addPhonyCmd(name: cmdName, inputs: outputs, outputs: [.virtual(cmdName)])
5050

5151
return .virtual(cmdName)

Sources/Build/BuildManifest/LLBuildManifestBuilder+Swift.swift

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension LLBuildManifestBuilder {
4545
let moduleNode = Node.file(target.moduleOutputPath)
4646
let cmdOutputs = objectNodes + [moduleNode]
4747

48-
if target.defaultBuildParameters.driverParameters.useIntegratedSwiftDriver {
48+
if target.buildParameters.driverParameters.useIntegratedSwiftDriver {
4949
try self.addSwiftCmdsViaIntegratedDriver(
5050
target,
5151
inputs: inputs,
@@ -68,7 +68,7 @@ extension LLBuildManifestBuilder {
6868
// jobs needed to build this Swift target.
6969
var commandLine = try target.emitCommandLine()
7070
commandLine.append("-driver-use-frontend-path")
71-
commandLine.append(target.defaultBuildParameters.toolchain.swiftCompilerPath.pathString)
71+
commandLine.append(target.buildParameters.toolchain.swiftCompilerPath.pathString)
7272
// FIXME: At some point SwiftPM should provide its own executor for
7373
// running jobs/launching processes during planning
7474
let resolver = try ArgsResolver(fileSystem: target.fileSystem)
@@ -132,7 +132,7 @@ extension LLBuildManifestBuilder {
132132
// common intermediate dependency modules, such dependencies can lead
133133
// to cycles in the resulting manifest.
134134
var manifestNodeInputs: [Node] = []
135-
if targetDescription.defaultBuildParameters.driverParameters.useExplicitModuleBuild && !isMainModule(job) {
135+
if targetDescription.buildParameters.driverParameters.useExplicitModuleBuild && !isMainModule(job) {
136136
manifestNodeInputs = jobInputs
137137
} else {
138138
manifestNodeInputs = (inputs + jobInputs).uniqued()
@@ -191,11 +191,8 @@ extension LLBuildManifestBuilder {
191191
public func addTargetsToExplicitBuildManifest() throws {
192192
// Sort the product targets in topological order in order to collect and "bubble up"
193193
// their respective dependency graphs to the depending targets.
194-
let nodes: [ResolvedModule.Dependency] = try self.plan.targetMap.keys.compactMap {
195-
guard let target = self.plan.graph.allTargets[$0] else {
196-
throw InternalError("unknown target \($0)")
197-
}
198-
return ResolvedModule.Dependency.target(target, conditions: [])
194+
let nodes = self.plan.targets.compactMap {
195+
ResolvedModule.Dependency.target($0.target, conditions: [])
199196
}
200197
let allPackageDependencies = try topologicalSort(nodes, successors: { $0.dependencies })
201198
// Instantiate the inter-module dependency oracle which will cache commonly-scanned
@@ -287,7 +284,7 @@ extension LLBuildManifestBuilder {
287284
// jobs needed to build this Swift target.
288285
var commandLine = try targetDescription.emitCommandLine()
289286
commandLine.append("-driver-use-frontend-path")
290-
commandLine.append(targetDescription.defaultBuildParameters.toolchain.swiftCompilerPath.pathString)
287+
commandLine.append(targetDescription.buildParameters.toolchain.swiftCompilerPath.pathString)
291288
commandLine.append("-experimental-explicit-module-build")
292289
let resolver = try ArgsResolver(fileSystem: self.fileSystem)
293290
let executor = SPMSwiftDriverExecutor(
@@ -378,14 +375,14 @@ extension LLBuildManifestBuilder {
378375
cmdOutputs: [Node]
379376
) throws {
380377
let isLibrary = target.target.type == .library || target.target.type == .test
381-
let cmdName = target.target.getCommandName(buildParameters: target.defaultBuildParameters)
378+
let cmdName = target.getCommandName()
382379

383380
self.manifest.addWriteSourcesFileListCommand(sources: target.sources, sourcesFileListPath: target.sourcesFileListPath)
384381
self.manifest.addSwiftCmd(
385382
name: cmdName,
386383
inputs: inputs + [Node.file(target.sourcesFileListPath)],
387384
outputs: cmdOutputs,
388-
executable: target.defaultBuildParameters.toolchain.swiftCompilerPath,
385+
executable: target.buildParameters.toolchain.swiftCompilerPath,
389386
moduleName: target.target.c99name,
390387
moduleAliases: target.target.moduleAliases,
391388
moduleOutputPath: target.moduleOutputPath,
@@ -396,7 +393,7 @@ extension LLBuildManifestBuilder {
396393
sources: target.sources,
397394
fileList: target.sourcesFileListPath,
398395
isLibrary: isLibrary,
399-
wholeModuleOptimization: target.defaultBuildParameters.configuration == .release,
396+
wholeModuleOptimization: target.buildParameters.configuration == .release,
400397
outputFileMapPath: try target.writeOutputFileMap() // FIXME: Eliminate side effect.
401398
)
402399
}
@@ -406,7 +403,7 @@ extension LLBuildManifestBuilder {
406403
) throws -> [Node] {
407404
var inputs = target.sources.map(Node.file)
408405

409-
let swiftVersionFilePath = addSwiftGetVersionCommand(buildParameters: target.defaultBuildParameters)
406+
let swiftVersionFilePath = addSwiftGetVersionCommand(buildParameters: target.buildParameters)
410407
inputs.append(.file(swiftVersionFilePath))
411408

412409
// Add resources node as the input to the target. This isn't great because we
@@ -433,14 +430,10 @@ extension LLBuildManifestBuilder {
433430
// Depend on the binary for executable targets.
434431
if target.type == .executable {
435432
// FIXME: Optimize.
436-
let product = try plan.graph.allProducts.first {
437-
try $0.type == .executable && $0.executableTarget.id == target.id
438-
}
439-
if let product {
440-
guard let planProduct = plan.productMap[product.id] else {
441-
throw InternalError("unknown product \(product)")
442-
}
443-
try inputs.append(file: planProduct.binaryPath)
433+
if let productDescription = try plan.productMap.values.first(where: {
434+
try $0.product.type == .executable && $0.product.executableTarget.id == target.id
435+
}) {
436+
try inputs.append(file: productDescription.binaryPath)
444437
}
445438
return
446439
}
@@ -457,7 +450,7 @@ extension LLBuildManifestBuilder {
457450
}
458451
}
459452

460-
for dependency in target.target.dependencies(satisfying: target.defaultBuildParameters.buildEnvironment) {
453+
for dependency in target.target.dependencies(satisfying: target.buildParameters.buildEnvironment) {
461454
switch dependency {
462455
case .target(let target, _):
463456
try addStaticTargetInputs(target)
@@ -484,7 +477,7 @@ extension LLBuildManifestBuilder {
484477
}
485478

486479
for binaryPath in target.libraryBinaryPaths {
487-
let path = target.defaultBuildParameters.destinationPath(forBinaryAt: binaryPath)
480+
let path = target.buildParameters.destinationPath(forBinaryAt: binaryPath)
488481
if self.fileSystem.isDirectory(binaryPath) {
489482
inputs.append(directory: path)
490483
} else {
@@ -496,7 +489,7 @@ extension LLBuildManifestBuilder {
496489

497490
// Depend on any required macro product's output.
498491
try target.requiredMacroProducts.forEach { macro in
499-
try inputs.append(.virtual(macro.getLLBuildTargetName(buildParameters: target.defaultBuildParameters)))
492+
try inputs.append(.virtual(macro.llbuildTargetName))
500493
}
501494

502495
return inputs + additionalInputs
@@ -505,7 +498,7 @@ extension LLBuildManifestBuilder {
505498
/// Adds a top-level phony command that builds the entire target.
506499
private func addTargetCmd(_ target: SwiftTargetBuildDescription, cmdOutputs: [Node]) {
507500
// Create a phony node to represent the entire target.
508-
let targetName = target.target.getLLBuildTargetName(buildParameters: target.defaultBuildParameters)
501+
let targetName = target.getLLBuildTargetName()
509502
let targetOutput: Node = .virtual(targetName)
510503

511504
self.manifest.addNode(targetOutput, toTarget: targetName)
@@ -514,7 +507,7 @@ extension LLBuildManifestBuilder {
514507
inputs: cmdOutputs,
515508
outputs: [targetOutput]
516509
)
517-
if self.plan.graph.isInRootPackages(target.target, satisfying: target.defaultBuildParameters.buildEnvironment) {
510+
if self.plan.graph.isInRootPackages(target.target, satisfying: target.buildParameters.buildEnvironment) {
518511
if !target.isTestTarget {
519512
self.addNode(targetOutput, toTarget: .main)
520513
}
@@ -524,13 +517,13 @@ extension LLBuildManifestBuilder {
524517

525518
private func addModuleWrapCmd(_ target: SwiftTargetBuildDescription) throws {
526519
// Add commands to perform the module wrapping Swift modules when debugging strategy is `modulewrap`.
527-
guard target.defaultBuildParameters.debuggingStrategy == .modulewrap else { return }
520+
guard target.buildParameters.debuggingStrategy == .modulewrap else { return }
528521
var moduleWrapArgs = [
529-
target.defaultBuildParameters.toolchain.swiftCompilerPath.pathString,
522+
target.buildParameters.toolchain.swiftCompilerPath.pathString,
530523
"-modulewrap", target.moduleOutputPath.pathString,
531524
"-o", target.wrappedModuleOutputPath.pathString,
532525
]
533-
moduleWrapArgs += try target.defaultBuildParameters.tripleArgs(for: target.target)
526+
moduleWrapArgs += try target.buildParameters.tripleArgs(for: target.target)
534527
self.manifest.addShellCmd(
535528
name: target.wrappedModuleOutputPath.pathString,
536529
description: "Wrapping AST for \(target.target.name) for debugging",
@@ -611,3 +604,13 @@ extension Driver {
611604
}
612605
}
613606
}
607+
608+
extension SwiftTargetBuildDescription {
609+
public func getCommandName() -> String {
610+
"C." + self.getLLBuildTargetName()
611+
}
612+
613+
public func getLLBuildTargetName() -> String {
614+
self.target.getLLBuildTargetName(buildParameters: self.buildParameters)
615+
}
616+
}

Sources/Build/BuildManifest/LLBuildManifestBuilder.swift

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -316,52 +316,21 @@ extension TargetBuildDescription {
316316
}
317317
}
318318

319-
extension ResolvedModule {
320-
public func getCommandName(buildParameters: BuildParameters) -> String {
321-
"C." + self.getLLBuildTargetName(buildParameters: buildParameters)
322-
}
323-
324-
public func getLLBuildTargetName(buildParameters: BuildParameters) -> String {
325-
"\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module"
326-
}
327-
328-
public func getLLBuildResourcesCmdName(buildParameters: BuildParameters) -> String {
329-
"\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix(triple: self.buildTriple)).module-resources"
319+
extension TargetBuildDescription {
320+
package var llbuildResourcesCmdName: String {
321+
"\(self.target.name)-\(self.buildParameters.triple.tripleString)-\(self.buildParameters.buildConfig)\(self.buildParameters.suffix).module-resources"
330322
}
331323
}
332324

333-
extension ResolvedProduct {
334-
public func getLLBuildTargetName(buildParameters: BuildParameters) throws -> String {
335-
let triple = buildParameters.triple.tripleString
336-
let config = buildParameters.buildConfig
337-
let suffix = buildParameters.suffix(triple: self.buildTriple)
338-
let potentialExecutableTargetName = "\(name)-\(triple)-\(config)\(suffix).exe"
339-
let potentialLibraryTargetName = "\(name)-\(triple)-\(config)\(suffix).dylib"
340-
341-
switch type {
342-
case .library(.dynamic):
343-
return potentialLibraryTargetName
344-
case .test:
345-
return "\(name)-\(triple)-\(config)\(suffix).test"
346-
case .library(.static):
347-
return "\(name)-\(triple)-\(config)\(suffix).a"
348-
case .library(.automatic):
349-
throw InternalError("automatic library not supported")
350-
case .executable, .snippet:
351-
return potentialExecutableTargetName
352-
case .macro:
353-
#if BUILD_MACROS_AS_DYLIBS
354-
return potentialLibraryTargetName
355-
#else
356-
return potentialExecutableTargetName
357-
#endif
358-
case .plugin:
359-
throw InternalError("unexpectedly asked for the llbuild target name of a plugin product")
360-
}
325+
extension ClangTargetBuildDescription {
326+
package var llbuildTargetName: String {
327+
self.target.getLLBuildTargetName(buildParameters: self.buildParameters)
361328
}
329+
}
362330

363-
public func getCommandName(buildParameters: BuildParameters) throws -> String {
364-
try "C.\(self.getLLBuildTargetName(buildParameters: buildParameters))\(buildParameters.suffix(triple: self.buildTriple))"
331+
extension ResolvedModule {
332+
public func getLLBuildTargetName(buildParameters: BuildParameters) -> String {
333+
"\(self.name)-\(buildParameters.triple.tripleString)-\(buildParameters.buildConfig)\(buildParameters.suffix).module"
365334
}
366335
}
367336

0 commit comments

Comments
 (0)