Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify bootstrap build #5939

Merged
merged 3 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,9 @@ let package = Package(
"Basics",
"Build",
"PackageFingerprint",
"PackageLoading",
"PackageModel",
"PackageGraph",
"Workspace",
"XCBuildSupport",
],
Expand Down Expand Up @@ -389,7 +391,15 @@ let package = Package(
.executableTarget(
/** Builds SwiftPM itself for bootstrapping (minimal version of `swift-build`) */
name: "swift-bootstrap",
dependencies: ["CoreCommands"],
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"Basics",
"Build",
"PackageGraph",
"PackageLoading",
"PackageModel",
"XCBuildSupport",
],
exclude: ["CMakeLists.txt"]
),
.executableTarget(
Expand Down
119 changes: 71 additions & 48 deletions Sources/Build/BuildOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import protocol TSCUtility.ProgressAnimationProtocol
@_implementationOnly import SwiftDriver

public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildSystem, BuildErrorAdviceProvider {

/// The delegate used by the build system.
public weak var delegate: SPMBuildCore.BuildSystemDelegate?

Expand All @@ -39,14 +38,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
/// The closure for loading the package graph.
let packageGraphLoader: () throws -> PackageGraph

/// Entity responsible for compiling and running plugin scripts.
let pluginScriptRunner: PluginScriptRunner

/// Directory where plugin intermediate files are stored.
let pluginWorkDirectory: AbsolutePath

/// Whether to sandbox commands from build tool plugins.
public let disableSandboxForPluginCommands: Bool
/// the plugin configuration for build plugins
let pluginConfiguration: PluginConfiguration?

/// The llbuild build delegate reference.
private var buildSystemDelegate: BuildOperationBuildSystemDelegateHandler?
Expand Down Expand Up @@ -99,10 +92,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
buildParameters: BuildParameters,
cacheBuildManifest: Bool,
packageGraphLoader: @escaping () throws -> PackageGraph,
pluginConfiguration: PluginConfiguration? = .none,
additionalFileRules: [FileRuleDescription],
pluginScriptRunner: PluginScriptRunner,
pluginWorkDirectory: AbsolutePath,
disableSandboxForPluginCommands: Bool,
outputStream: OutputByteStream,
logLevel: Basics.Diagnostic.Severity,
fileSystem: TSCBasic.FileSystem,
Expand All @@ -116,9 +107,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
self.cacheBuildManifest = cacheBuildManifest
self.packageGraphLoader = packageGraphLoader
self.additionalFileRules = additionalFileRules
self.pluginScriptRunner = pluginScriptRunner
self.pluginWorkDirectory = pluginWorkDirectory
self.disableSandboxForPluginCommands = disableSandboxForPluginCommands
self.pluginConfiguration = pluginConfiguration
self.outputStream = outputStream
self.logLevel = logLevel
self.fileSystem = fileSystem
Expand Down Expand Up @@ -323,6 +312,10 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
// Compiles a single plugin, emitting its output and throwing an error if it
// fails.
func compilePlugin(_ plugin: PluginDescription) throws {
guard let pluginConfiguration = self.pluginConfiguration else {
throw InternalError("unknown plugin script runner")

}
// Compile the plugin, getting back a PluginCompilationResult.
class Delegate: PluginScriptCompilerDelegate {
let preparationStepName: String
Expand Down Expand Up @@ -351,7 +344,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
}
let delegate = Delegate(preparationStepName: "Compiling plugin \(plugin.targetName)", buildSystemDelegate: self.buildSystemDelegate)
let result = try tsc_await {
self.pluginScriptRunner.compilePluginScript(
pluginConfiguration.scriptRunner.compilePluginScript(
sourceFiles: plugin.sources.paths,
pluginName: plugin.targetName,
toolsVersion: plugin.toolsVersion,
Expand Down Expand Up @@ -393,40 +386,47 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
// Load the package graph.
let graph = try getPackageGraph()

let buildToolPluginInvocationResults: [ResolvedTarget: [BuildToolPluginInvocationResult]]
let prebuildCommandResults: [ResolvedTarget: [PrebuildCommandResult]]
// Invoke any build tool plugins in the graph to generate prebuild commands and build commands.
let buildToolPluginInvocationResults = try graph.invokeBuildToolPlugins(
outputDir: self.pluginWorkDirectory.appending(component: "outputs"),
builtToolsDir: self.buildParameters.buildPath,
buildEnvironment: self.buildParameters.buildEnvironment,
toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory],
pluginScriptRunner: self.pluginScriptRunner,
observabilityScope: self.observabilityScope,
fileSystem: self.fileSystem
)

// Surface any diagnostics from build tool plugins.
for (target, results) in buildToolPluginInvocationResults {
// There is one result for each plugin that gets applied to a target.
for result in results {
let diagnosticsEmitter = self.observabilityScope.makeDiagnosticsEmitter {
var metadata = ObservabilityMetadata()
metadata.targetName = target.name
metadata.pluginName = result.plugin.name
return metadata
}
for line in result.textOutput.split(separator: "\n") {
diagnosticsEmitter.emit(info: line)
}
for diag in result.diagnostics {
diagnosticsEmitter.emit(diag)
if let pluginConfiguration = self.pluginConfiguration {
buildToolPluginInvocationResults = try graph.invokeBuildToolPlugins(
outputDir: pluginConfiguration.workDirectory.appending(component: "outputs"),
builtToolsDir: self.buildParameters.buildPath,
buildEnvironment: self.buildParameters.buildEnvironment,
toolSearchDirectories: [self.buildParameters.toolchain.swiftCompilerPath.parentDirectory],
pluginScriptRunner: pluginConfiguration.scriptRunner,
observabilityScope: self.observabilityScope,
fileSystem: self.fileSystem
)

// Surface any diagnostics from build tool plugins.
for (target, results) in buildToolPluginInvocationResults {
// There is one result for each plugin that gets applied to a target.
for result in results {
let diagnosticsEmitter = self.observabilityScope.makeDiagnosticsEmitter {
var metadata = ObservabilityMetadata()
metadata.targetName = target.name
metadata.pluginName = result.plugin.name
return metadata
}
for line in result.textOutput.split(separator: "\n") {
diagnosticsEmitter.emit(info: line)
}
for diag in result.diagnostics {
diagnosticsEmitter.emit(diag)
}
}
}
}

// Run any prebuild commands provided by build tool plugins. Any failure stops the build.
let prebuildCommandResults = try graph.reachableTargets.reduce(into: [:], { partial, target in
partial[target] = try buildToolPluginInvocationResults[target].map { try self.runPrebuildCommands(for: $0) }
})
// Run any prebuild commands provided by build tool plugins. Any failure stops the build.
prebuildCommandResults = try graph.reachableTargets.reduce(into: [:], { partial, target in
partial[target] = try buildToolPluginInvocationResults[target].map { try self.runPrebuildCommands(for: $0) }
})
} else {
buildToolPluginInvocationResults = [:]
prebuildCommandResults = [:]
}

// Emit warnings about any unhandled files in authored packages. We do this after applying build tool plugins, once we know what files they handled.
for package in graph.rootPackages where package.manifest.toolsVersion >= .v5_3 {
Expand Down Expand Up @@ -472,7 +472,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS

let (buildDescription, buildManifest) = try BuildDescription.create(
with: plan,
disableSandboxForPluginCommands: self.disableSandboxForPluginCommands,
disableSandboxForPluginCommands: self.pluginConfiguration?.disableSandbox ?? false,
fileSystem: self.fileSystem,
observabilityScope: self.observabilityScope
)
Expand Down Expand Up @@ -541,6 +541,10 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
/// Runs any prebuild commands associated with the given list of plugin invocation results, in order, and returns the
/// results of running those prebuild commands.
private func runPrebuildCommands(for pluginResults: [BuildToolPluginInvocationResult]) throws -> [PrebuildCommandResult] {
guard let pluginConfiguration = self.pluginConfiguration else {
throw InternalError("unknown plugin script runner")

}
// Run through all the commands from all the plugin usages in the target.
return try pluginResults.map { pluginResult in
// As we go we will collect a list of prebuild output directories whose contents should be input to the build,
Expand All @@ -553,7 +557,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
// Run the command configuration as a subshell. This doesn't return until it is done.
// TODO: We need to also use any working directory, but that support isn't yet available on all platforms at a lower level.
var commandLine = [command.configuration.executable.pathString] + command.configuration.arguments
if !self.disableSandboxForPluginCommands {
if !pluginConfiguration.disableSandbox {
commandLine = try Sandbox.apply(command: commandLine, strictness: .writableTemporaryDirectory, writableDirectories: [pluginResult.pluginOutputDirectory])
}
let processResult = try TSCBasic.Process.popen(arguments: commandLine, environment: command.configuration.environment)
Expand Down Expand Up @@ -613,6 +617,25 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
}
}

extension BuildOperation {
public struct PluginConfiguration {
/// Entity responsible for compiling and running plugin scripts.
let scriptRunner: PluginScriptRunner

/// Directory where plugin intermediate files are stored.
let workDirectory: AbsolutePath

/// Whether to sandbox commands from build tool plugins.
let disableSandbox: Bool

public init(scriptRunner: PluginScriptRunner, workDirectory: AbsolutePath, disableSandbox: Bool) {
self.scriptRunner = scriptRunner
self.workDirectory = workDirectory
self.disableSandbox = disableSandbox
}
}
}

extension BuildDescription {
static func create(with plan: BuildPlan, disableSandboxForPluginCommands: Bool, fileSystem: TSCBasic.FileSystem, observabilityScope: ObservabilityScope) throws -> (BuildDescription, LLBuildManifest.BuildManifest) {
// Generate the llbuild manifest.
Expand Down
8 changes: 5 additions & 3 deletions Sources/CoreCommands/BuildSystemSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ extension SwiftTool {
buildParameters: customBuildParameters ?? self.buildParameters(),
cacheBuildManifest: cacheBuildManifest && self.canUseCachedBuildManifest(),
packageGraphLoader: customPackageGraphLoader ?? graphLoader,
pluginConfiguration: .init(
scriptRunner: self.getPluginScriptRunner(),
workDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory,
disableSandbox: self.options.security.shouldDisableSandbox
),
additionalFileRules: FileRuleDescription.swiftpmFileTypes,
pluginScriptRunner: self.getPluginScriptRunner(),
pluginWorkDirectory: try self.getActiveWorkspace().location.pluginWorkingDirectory,
disableSandboxForPluginCommands: self.options.security.shouldDisableSandbox,
outputStream: customOutputStream ?? self.outputStream,
logLevel: customLogLevel ?? self.logLevel,
fileSystem: self.fileSystem,
Expand Down
1 change: 0 additions & 1 deletion Sources/CoreCommands/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

add_library(CoreCommands
BuildSystemSupport.swift
MinimalBuildTool.swift
SwiftTool.swift
SwiftToolObservabilityHandler.swift
Options.swift)
Expand Down
86 changes: 0 additions & 86 deletions Sources/CoreCommands/MinimalBuildTool.swift

This file was deleted.

17 changes: 11 additions & 6 deletions Sources/CoreCommands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ public protocol SwiftCommand: ParsableCommand {

extension SwiftCommand {
public func run() throws {
let swiftTool = try SwiftTool(options: globalOptions, toolWorkspaceConfiguration: self.toolWorkspaceConfiguration, workspaceDelegateProvider: self.workspaceDelegateProvider, workspaceLoaderProvider: self.workspaceLoaderProvider)
let swiftTool = try SwiftTool(
options: globalOptions,
toolWorkspaceConfiguration: self.toolWorkspaceConfiguration,
workspaceDelegateProvider: self.workspaceDelegateProvider,
workspaceLoaderProvider: self.workspaceLoaderProvider
)
swiftTool.buildSystemProvider = try buildSystemProvider(swiftTool)
var toolError: Error? = .none
do {
Expand Down Expand Up @@ -575,19 +580,19 @@ public final class SwiftTool {

private lazy var _buildParameters: Result<BuildParameters, Swift.Error> = {
return Result(catching: {
let toolchain = try self.getDestinationToolchain()
let triple = toolchain.triple
let destinationToolchain = try self.getDestinationToolchain()
let destinationTriple = destinationToolchain.triple

// Use "apple" as the subdirectory because in theory Xcode build system
// can be used to build for any Apple platform and it has it's own
// conventions for build subpaths based on platforms.
let dataPath = self.scratchDirectory.appending(
component: options.build.buildSystem == .xcode ? "apple" : triple.platformBuildPathComponent())
component: options.build.buildSystem == .xcode ? "apple" : destinationTriple.platformBuildPathComponent())
return BuildParameters(
dataPath: dataPath,
configuration: options.build.configuration,
toolchain: toolchain,
destinationTriple: triple,
toolchain: destinationToolchain,
destinationTriple: destinationTriple,
archs: options.build.archs,
flags: options.build.buildFlags,
xcbuildFlags: options.build.xcbuildFlags,
Expand Down
Loading