From 5ec40eec722b325a290180bc82611831d2e08e79 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 3 Dec 2024 15:20:05 +0000 Subject: [PATCH 1/3] Unify `swift-bootstrap` with `swift-build` and `swift-test` This is a prerequisite for enabling incremental builds when running `./Utillities/bootstrap build --release` and `./Utilities/bootstrap test --release` in sequence. --- Package.swift | 1 + Sources/Commands/CMakeLists.txt | 1 - Sources/Commands/SwiftBuildCommand.swift | 6 - .../Commands/Utilities/MultiRootSupport.swift | 8 + Sources/CoreCommands/CMakeLists.txt | 1 + .../CommandWorkspaceDelegate.swift | 7 - Sources/CoreCommands/SwiftCommandState.swift | 6 + Sources/swift-bootstrap/CMakeLists.txt | 7 +- .../SwiftBootstrapCommand.swift | 69 +++ Sources/swift-bootstrap/main.swift | 530 ------------------ 10 files changed, 91 insertions(+), 545 deletions(-) rename Sources/{Commands => CoreCommands}/CommandWorkspaceDelegate.swift (98%) create mode 100644 Sources/swift-bootstrap/SwiftBootstrapCommand.swift delete mode 100644 Sources/swift-bootstrap/main.swift diff --git a/Package.swift b/Package.swift index 235acef7228..3964f45e5a0 100644 --- a/Package.swift +++ b/Package.swift @@ -602,6 +602,7 @@ let package = Package( .product(name: "ArgumentParser", package: "swift-argument-parser"), "Basics", "Build", + "CoreCommands", "PackageGraph", "PackageLoading", "PackageModel", diff --git a/Sources/Commands/CMakeLists.txt b/Sources/Commands/CMakeLists.txt index 3c273289783..1fc2de13994 100644 --- a/Sources/Commands/CMakeLists.txt +++ b/Sources/Commands/CMakeLists.txt @@ -41,7 +41,6 @@ add_library(Commands SwiftBuildCommand.swift SwiftRunCommand.swift SwiftTestCommand.swift - CommandWorkspaceDelegate.swift Utilities/APIDigester.swift Utilities/DependenciesSerializer.swift Utilities/DescribedPackage.swift diff --git a/Sources/Commands/SwiftBuildCommand.swift b/Sources/Commands/SwiftBuildCommand.swift index 76ff6c09322..1552fec9d6e 100644 --- a/Sources/Commands/SwiftBuildCommand.swift +++ b/Sources/Commands/SwiftBuildCommand.swift @@ -191,9 +191,3 @@ public struct SwiftBuildCommand: AsyncSwiftCommand { public init() {} } - -public extension _SwiftCommand { - func buildSystemProvider(_ swiftCommandState: SwiftCommandState) throws -> BuildSystemProvider { - swiftCommandState.defaultBuildSystemProvider - } -} diff --git a/Sources/Commands/Utilities/MultiRootSupport.swift b/Sources/Commands/Utilities/MultiRootSupport.swift index 7ee468a81f5..1dbb907b589 100644 --- a/Sources/Commands/Utilities/MultiRootSupport.swift +++ b/Sources/Commands/Utilities/MultiRootSupport.swift @@ -110,3 +110,11 @@ public struct XcodeWorkspaceLoader: WorkspaceLoader { } } } + +public extension _SwiftCommand { + var workspaceLoaderProvider: WorkspaceLoaderProvider { + return { + XcodeWorkspaceLoader(fileSystem: $0, observabilityScope: $1) + } + } +} diff --git a/Sources/CoreCommands/CMakeLists.txt b/Sources/CoreCommands/CMakeLists.txt index d7ec0cbb632..b504c9d1d81 100644 --- a/Sources/CoreCommands/CMakeLists.txt +++ b/Sources/CoreCommands/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(CoreCommands BuildSystemSupport.swift + CommandWorkspaceDelegate.swift SwiftCommandState.swift SwiftCommandObservabilityHandler.swift Options.swift) diff --git a/Sources/Commands/CommandWorkspaceDelegate.swift b/Sources/CoreCommands/CommandWorkspaceDelegate.swift similarity index 98% rename from Sources/Commands/CommandWorkspaceDelegate.swift rename to Sources/CoreCommands/CommandWorkspaceDelegate.swift index accec9fe9a3..c70e79a3847 100644 --- a/Sources/Commands/CommandWorkspaceDelegate.swift +++ b/Sources/CoreCommands/CommandWorkspaceDelegate.swift @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// import Basics -import CoreCommands import Dispatch import class Foundation.NSLock import struct Foundation.URL @@ -275,10 +274,4 @@ public extension _SwiftCommand { ) } } - - var workspaceLoaderProvider: WorkspaceLoaderProvider { - return { - XcodeWorkspaceLoader(fileSystem: $0, observabilityScope: $1) - } - } } diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index 8a7f714164a..8279749d78b 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -1185,3 +1185,9 @@ extension Basics.Diagnostic { .error(arguments.map { "'\($0)'" }.spm_localizedJoin(type: .conjunction) + " are mutually exclusive") } } + +public extension _SwiftCommand { + func buildSystemProvider(_ swiftCommandState: SwiftCommandState) throws -> BuildSystemProvider { + swiftCommandState.defaultBuildSystemProvider + } +} diff --git a/Sources/swift-bootstrap/CMakeLists.txt b/Sources/swift-bootstrap/CMakeLists.txt index 92052ac7098..e89e47d2c73 100644 --- a/Sources/swift-bootstrap/CMakeLists.txt +++ b/Sources/swift-bootstrap/CMakeLists.txt @@ -7,11 +7,16 @@ # See http://swift.org/CONTRIBUTORS.txt for Swift project authors add_executable(swift-bootstrap - main.swift) + SwiftBootstrapCommand.swift) + +target_compile_options(swift-bootstrap PRIVATE + -parse-as-library) + target_link_libraries(swift-bootstrap PRIVATE ArgumentParser Basics Build + CoreCommands PackageGraph PackageLoading PackageModel diff --git a/Sources/swift-bootstrap/SwiftBootstrapCommand.swift b/Sources/swift-bootstrap/SwiftBootstrapCommand.swift new file mode 100644 index 00000000000..1081a7557a3 --- /dev/null +++ b/Sources/swift-bootstrap/SwiftBootstrapCommand.swift @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2022-2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import ArgumentParser +import Basics +import _Concurrency +import Build +import CoreCommands +import Dispatch + +@_spi(SwiftPMInternal) +import DriverSupport + +import Foundation +import OrderedCollections +import PackageGraph +import PackageLoading +import PackageModel +import SPMBuildCore +import XCBuildSupport + +import struct TSCBasic.KeyedPair +import var TSCBasic.stdoutStream +import enum TSCBasic.GraphError +import struct TSCBasic.OrderedSet +import enum TSCUtility.Diagnostics +import struct TSCUtility.Version + +@main +struct SwiftBootstrapCommand: AsyncSwiftCommand { + /// If the test should be built. + @Flag(help: "Build both source and test targets") + var buildTests: Bool = false + + @OptionGroup(visibility: .hidden) + var globalOptions: GlobalOptions + + var workspaceLoaderProvider: CoreCommands.WorkspaceLoaderProvider { + { _, _ in EmptyWorkspaceLoader() } + } + + static let configuration = CommandConfiguration( + commandName: "swift-bootstrap", + abstract: "Bootstrapping build tool, only use in the context of bootstrapping SwiftPM itself", + shouldDisplay: false + ) + + public init() {} + + public func run(_ swiftCommandState: SwiftCommandState) async throws { + let buildSystem = try await swiftCommandState.createBuildSystem(traitConfiguration: .init()) + try await buildSystem.build(subset: self.buildTests ? .allIncludingTests : .allExcludingTests) + } +} + +private struct EmptyWorkspaceLoader: WorkspaceLoader { + func load(workspace: AbsolutePath) throws -> [AbsolutePath] { + [] + } +} diff --git a/Sources/swift-bootstrap/main.swift b/Sources/swift-bootstrap/main.swift deleted file mode 100644 index 61d179994e7..00000000000 --- a/Sources/swift-bootstrap/main.swift +++ /dev/null @@ -1,530 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 2022-2024 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import ArgumentParser -import Basics -import _Concurrency -import Build -import Dispatch - -@_spi(SwiftPMInternal) -import DriverSupport - -import Foundation -import OrderedCollections -import PackageGraph -import PackageLoading -import PackageModel -import SPMBuildCore -import XCBuildSupport - -import struct TSCBasic.KeyedPair -import func TSCBasic.topologicalSort -import var TSCBasic.stdoutStream -import enum TSCBasic.GraphError -import struct TSCBasic.OrderedSet -import enum TSCUtility.Diagnostics -import struct TSCUtility.Version - -await { () async in - await SwiftBootstrapBuildTool.main() -}() - -struct SwiftBootstrapBuildTool: AsyncParsableCommand { - static let configuration = CommandConfiguration( - commandName: "swift-bootstrap", - abstract: "Bootstrapping build tool, only use in the context of bootstrapping SwiftPM itself", - shouldDisplay: false - ) - - @Option(name: .customLong("package-path"), - help: "Specify the package path to operate on (default current directory). This changes the working directory before any other operation", - completion: .directory) - public var packageDirectory: AbsolutePath? - - /// The custom .build directory, if provided. - @Option(name: .customLong("scratch-path"), help: "Specify a custom scratch directory path (default .build)", completion: .directory) - var _scratchDirectory: AbsolutePath? - - @Option(name: .customLong("build-path"), help: .hidden) - var _deprecated_buildPath: AbsolutePath? - - var scratchDirectory: AbsolutePath? { - self._scratchDirectory ?? self._deprecated_buildPath - } - - @Option(name: .shortAndLong, help: "Build with configuration") - public var configuration: BuildConfiguration = .debug - - @Option(name: .customLong("Xcc", withSingleDash: true), - parsing: .unconditionalSingleValue, - help: "Pass flag through to all C compiler invocations") - var cCompilerFlags: [String] = [] - - @Option(name: .customLong("Xswiftc", withSingleDash: true), - parsing: .unconditionalSingleValue, - help: "Pass flag through to all Swift compiler invocations") - var swiftCompilerFlags: [String] = [] - - @Option(name: .customLong("Xlinker", withSingleDash: true), - parsing: .unconditionalSingleValue, - help: "Pass flag through to all linker invocations") - var linkerFlags: [String] = [] - - @Option(name: .customLong("Xcxx", withSingleDash: true), - parsing: .unconditionalSingleValue, - help: "Pass flag through to all C++ compiler invocations") - var cxxCompilerFlags: [String] = [] - - @Option(name: .customLong("Xxcbuild", withSingleDash: true), - parsing: .unconditionalSingleValue, - help: ArgumentHelp( - "Pass flag through to the Xcode build system invocations", - visibility: .hidden)) - public var xcbuildFlags: [String] = [] - - @Option(name: .customLong("Xbuild-tools-swiftc", withSingleDash: true), - parsing: .unconditionalSingleValue, - help: ArgumentHelp("Pass flag to the manifest build invocation", - visibility: .hidden)) - public var manifestFlags: [String] = [] - - @Option( - name: .customLong("arch"), - help: ArgumentHelp("Build the package for the these architectures", visibility: .hidden)) - public var architectures: [String] = [] - - /// The verbosity of informational output. - @Flag(name: .shortAndLong, help: "Increase verbosity to include informational output") - public var verbose: Bool = false - - /// The verbosity of informational output. - @Flag(name: [.long, .customLong("vv")], help: "Increase verbosity to include debug output") - public var veryVerbose: Bool = false - - /// Whether to use the integrated Swift driver rather than shelling out - /// to a separate process. - @Flag() - public var useIntegratedSwiftDriver: Bool = false - - /// An option that indicates this build should check whether targets only import - /// their explicitly-declared dependencies - @Option(help: "Check that targets only import their explicitly-declared dependencies") - public var explicitTargetDependencyImportCheck: TargetDependencyImportCheckingMode = .none - - enum TargetDependencyImportCheckingMode: String, Codable, ExpressibleByArgument, CaseIterable { - case none - case error - } - - /// Disables adding $ORIGIN/@loader_path to the rpath, useful when deploying - @Flag(name: .customLong("disable-local-rpath"), help: "Disable adding $ORIGIN/@loader_path to the rpath by default") - public var shouldDisableLocalRpath: Bool = false - - private var buildSystem: BuildSystemProvider.Kind { - #if os(macOS) - // Force the Xcode build system if we want to build more than one arch. - return self.architectures.count > 1 ? .xcode : .native - #else - // Force building with the native build system on other platforms than macOS. - return .native - #endif - } - - public var buildFlags: BuildFlags { - BuildFlags( - cCompilerFlags: self.cCompilerFlags, - cxxCompilerFlags: self.cxxCompilerFlags, - swiftCompilerFlags: self.swiftCompilerFlags, - linkerFlags: self.linkerFlags, - xcbuildFlags: self.xcbuildFlags - ) - } - - private var logLevel: Basics.Diagnostic.Severity { - if self.verbose { - return .info - } else if self.veryVerbose { - return .debug - } else { - return .warning - } - } - - public init() {} - - public func run() async throws { - do { - let fileSystem = localFileSystem - - let observabilityScope = ObservabilitySystem { _, diagnostics in - if diagnostics.severity >= logLevel { - print(diagnostics) - } - }.topScope - - guard let cwd: AbsolutePath = fileSystem.currentWorkingDirectory else { - observabilityScope.emit(error: "couldn't determine the current working directory") - throw ExitCode.failure - } - - guard let packagePath = packageDirectory ?? localFileSystem.currentWorkingDirectory else { - throw StringError("unknown package path") - } - - let scratchDirectory = - try BuildSystemUtilities.getEnvBuildPath(workingDir: cwd) ?? - self.scratchDirectory ?? - packagePath.appending(".build") - - let builder = try Builder( - fileSystem: localFileSystem, - observabilityScope: observabilityScope, - logLevel: self.logLevel - ) - try await builder.build( - packagePath: packagePath, - scratchDirectory: scratchDirectory, - buildSystem: self.buildSystem, - configuration: self.configuration, - architectures: self.architectures, - buildFlags: self.buildFlags, - manifestBuildFlags: self.manifestFlags, - useIntegratedSwiftDriver: self.useIntegratedSwiftDriver, - explicitTargetDependencyImportCheck: self.explicitTargetDependencyImportCheck, - shouldDisableLocalRpath: self.shouldDisableLocalRpath - ) - } catch _ as Diagnostics { - throw ExitCode.failure - } - } - - struct Builder { - let identityResolver: IdentityResolver - let dependencyMapper: DependencyMapper - let hostToolchain: UserToolchain - let targetToolchain: UserToolchain - let fileSystem: FileSystem - let observabilityScope: ObservabilityScope - let logLevel: Basics.Diagnostic.Severity - - init(fileSystem: FileSystem, observabilityScope: ObservabilityScope, logLevel: Basics.Diagnostic.Severity) throws { - self.identityResolver = DefaultIdentityResolver() - self.dependencyMapper = DefaultDependencyMapper(identityResolver: self.identityResolver) - let environment = Environment.current - self.hostToolchain = try UserToolchain( - swiftSDK: SwiftSDK.hostSwiftSDK( - environment: environment, - fileSystem: fileSystem - ), - environment: environment - ) - self.targetToolchain = hostToolchain // TODO: support cross-compilation? - self.fileSystem = fileSystem - self.observabilityScope = observabilityScope - self.logLevel = logLevel - } - - func build( - packagePath: AbsolutePath, - scratchDirectory: AbsolutePath, - buildSystem: BuildSystemProvider.Kind, - configuration: BuildConfiguration, - architectures: [String], - buildFlags: BuildFlags, - manifestBuildFlags: [String], - useIntegratedSwiftDriver: Bool, - explicitTargetDependencyImportCheck: TargetDependencyImportCheckingMode, - shouldDisableLocalRpath: Bool - ) async throws { - let buildSystem = try createBuildSystem( - packagePath: packagePath, - scratchDirectory: scratchDirectory, - buildSystem: buildSystem, - configuration: configuration, - architectures: architectures, - buildFlags: buildFlags, - manifestBuildFlags: manifestBuildFlags, - useIntegratedSwiftDriver: useIntegratedSwiftDriver, - explicitTargetDependencyImportCheck: explicitTargetDependencyImportCheck, - shouldDisableLocalRpath: shouldDisableLocalRpath, - logLevel: logLevel - ) - try await buildSystem.build(subset: .allExcludingTests) - } - - func createBuildSystem( - packagePath: AbsolutePath, - scratchDirectory: AbsolutePath, - buildSystem: BuildSystemProvider.Kind, - configuration: BuildConfiguration, - architectures: [String], - buildFlags: BuildFlags, - manifestBuildFlags: [String], - useIntegratedSwiftDriver: Bool, - explicitTargetDependencyImportCheck: TargetDependencyImportCheckingMode, - shouldDisableLocalRpath: Bool, - logLevel: Basics.Diagnostic.Severity - ) throws -> BuildSystem { - var buildFlags = buildFlags - - let dataPath = scratchDirectory.appending( - component: self.targetToolchain.targetTriple.platformBuildPathComponent(buildSystem: buildSystem) - ) - - let buildParameters = try BuildParameters( - destination: .target, - dataPath: dataPath, - configuration: configuration, - toolchain: self.targetToolchain, - triple: self.hostToolchain.targetTriple, - flags: buildFlags, - architectures: architectures, - isXcodeBuildSystemEnabled: buildSystem == .xcode, - driverParameters: .init( - explicitTargetDependencyImportCheckingMode: explicitTargetDependencyImportCheck == .error ? .error : .none, - useIntegratedSwiftDriver: useIntegratedSwiftDriver, - isPackageAccessModifierSupported: DriverSupport.isPackageNameSupported( - toolchain: targetToolchain, - fileSystem: self.fileSystem - ) - ), - linkingParameters: .init( - shouldDisableLocalRpath: shouldDisableLocalRpath - ), - outputParameters: .init( - isVerbose: logLevel <= .info - ) - ) - - let manifestLoader = createManifestLoader(manifestBuildFlags: manifestBuildFlags) - - let asyncUnsafePackageGraphLoader = { - try await self.loadPackageGraph(packagePath: packagePath, manifestLoader: manifestLoader) - } - - switch buildSystem { - case .native: - let pluginScriptRunner = DefaultPluginScriptRunner( - fileSystem: self.fileSystem, - cacheDir: scratchDirectory.appending("plugin-cache"), - toolchain: self.hostToolchain, - extraPluginSwiftCFlags: [], - enableSandbox: true, - verboseOutput: self.logLevel <= .info - ) - return BuildOperation( - // when building `swift-bootstrap`, host and target build parameters are the same - productsBuildParameters: buildParameters, - toolsBuildParameters: buildParameters, - cacheBuildManifest: false, - packageGraphLoader: asyncUnsafePackageGraphLoader, - pluginConfiguration: .init( - scriptRunner: pluginScriptRunner, - workDirectory: scratchDirectory.appending(component: "plugin-working-directory"), - disableSandbox: false - ), - scratchDirectory: scratchDirectory, - // When bootrapping no special trait build configuration is used - traitConfiguration: nil, - additionalFileRules: [], - pkgConfigDirectories: [], - outputStream: TSCBasic.stdoutStream, - logLevel: logLevel, - fileSystem: self.fileSystem, - observabilityScope: self.observabilityScope - ) - case .xcode: - return try XcodeBuildSystem( - buildParameters: buildParameters, - packageGraphLoader: asyncUnsafePackageGraphLoader, - outputStream: TSCBasic.stdoutStream, - logLevel: logLevel, - fileSystem: self.fileSystem, - observabilityScope: self.observabilityScope - ) - } - } - - func createManifestLoader(manifestBuildFlags: [String]) -> ManifestLoader { - var extraManifestFlags = manifestBuildFlags - if self.logLevel <= .info { - extraManifestFlags.append("-v") - } - - return ManifestLoader( - toolchain: self.hostToolchain, - isManifestSandboxEnabled: false, - extraManifestFlags: extraManifestFlags - ) - } - - func loadPackageGraph(packagePath: AbsolutePath, manifestLoader: ManifestLoader) async throws -> ModulesGraph { - let rootPackageRef = PackageReference(identity: .init(path: packagePath), kind: .root(packagePath)) - let rootPackageManifest = try await self.loadManifest(manifestLoader: manifestLoader, package: rootPackageRef) - - var loadedManifests = [PackageIdentity: Manifest]() - loadedManifests[rootPackageRef.identity] = rootPackageManifest - - // Compute the transitive closure of available dependencies. - let input = loadedManifests.map { identity, manifest in KeyedPair(manifest, key: identity) } - _ = try await topologicalSort(input) { pair in - let dependenciesRequired = pair.item.dependenciesRequired(for: .everything) - let dependenciesToLoad = dependenciesRequired.map{ $0.packageRef }.filter { !loadedManifests.keys.contains($0.identity) } - let dependenciesManifests = try await self.loadManifests(manifestLoader: manifestLoader, packages: dependenciesToLoad) - dependenciesManifests.forEach { loadedManifests[$0.key] = $0.value } - return dependenciesRequired.compactMap { dependency in - loadedManifests[dependency.identity].flatMap { - KeyedPair($0, key: dependency.identity) - } - } - } - - let packageGraphRoot = PackageGraphRoot( - input: .init(packages: [packagePath]), - manifests: [packagePath: rootPackageManifest], - observabilityScope: observabilityScope - ) - - return try ModulesGraph.load( - root: packageGraphRoot, - identityResolver: identityResolver, - externalManifests: loadedManifests.reduce(into: OrderedCollections.OrderedDictionary()) { partial, item in - partial[item.key] = (manifest: item.value, fs: self.fileSystem) - }, - binaryArtifacts: [:], - fileSystem: fileSystem, - observabilityScope: observabilityScope - ) - } - - func loadManifests( - manifestLoader: ManifestLoader, - packages: [PackageReference] - ) async throws -> [PackageIdentity: Manifest] { - return try await withThrowingTaskGroup(of: (package:PackageReference, manifest:Manifest).self) { group in - for package in packages { - group.addTask { - try await (package, self.loadManifest(manifestLoader: manifestLoader, package: package)) - } - } - return try await group.reduce(into: [:]) { partialResult, packageManifest in - partialResult[packageManifest.package.identity] = packageManifest.manifest - } - } - } - - func loadManifest( - manifestLoader: ManifestLoader, - package: PackageReference - ) async throws -> Manifest { - let packagePath = try AbsolutePath(validating: package.locationString) // FIXME - let manifestPath = packagePath.appending(component: Manifest.filename) - let manifestToolsVersion = try ToolsVersionParser.parse(manifestPath: manifestPath, fileSystem: fileSystem) - return try await manifestLoader.load( - manifestPath: manifestPath, - manifestToolsVersion: manifestToolsVersion, - packageIdentity: package.identity, - packageKind: package.kind, - packageLocation: package.locationString, - packageVersion: .none, - identityResolver: identityResolver, - dependencyMapper: dependencyMapper, - fileSystem: fileSystem, - observabilityScope: observabilityScope, - delegateQueue: .sharedConcurrent, - callbackQueue: .sharedConcurrent - ) - } - } -} - -// TODO: move to shared area -extension AbsolutePath { - public init?(argument: String) { - if let cwd: AbsolutePath = localFileSystem.currentWorkingDirectory { - guard let path = try? AbsolutePath(validating: argument, relativeTo: cwd) else { - return nil - } - self = path - } else { - guard let path = try? AbsolutePath(validating: argument) else { - return nil - } - self = path - } - } - - public static var defaultCompletionKind: CompletionKind { - // This type is most commonly used to select a directory, not a file. - // Specify '.file()' in an argument declaration when necessary. - .directory - } -} - -extension BuildConfiguration { - public init?(argument: String) { - self.init(rawValue: argument) - } -} - -#if compiler(<6.0) -extension AbsolutePath: ExpressibleByArgument {} -extension BuildConfiguration: ExpressibleByArgument, CaseIterable {} -#else -extension AbsolutePath: @retroactive ExpressibleByArgument {} -extension BuildConfiguration: @retroactive ExpressibleByArgument, CaseIterable {} -#endif - -public func topologicalSort( - _ nodes: [T], successors: (T) async throws -> [T] -) async throws -> [T] { - // Implements a topological sort via recursion and reverse postorder DFS. - func visit(_ node: T, - _ stack: inout OrderedSet, _ visited: inout Set, _ result: inout [T], - _ successors: (T) async throws -> [T]) async throws { - // Mark this node as visited -- we are done if it already was. - if !visited.insert(node).inserted { - return - } - - // Otherwise, visit each adjacent node. - for succ in try await successors(node) { - guard stack.append(succ) else { - // If the successor is already in this current stack, we have found a cycle. - // - // FIXME: We could easily include information on the cycle we found here. - throw TSCBasic.GraphError.unexpectedCycle - } - try await visit(succ, &stack, &visited, &result, successors) - let popped = stack.removeLast() - assert(popped == succ) - } - - // Add to the result. - result.append(node) - } - - // FIXME: This should use a stack not recursion. - var visited = Set() - var result = [T]() - var stack = OrderedSet() - for node in nodes { - precondition(stack.isEmpty) - stack.append(node) - try await visit(node, &stack, &visited, &result, successors) - let popped = stack.removeLast() - assert(popped == node) - } - - return result.reversed() -} From 305771522c3bfeaa94361071f8c1edd02bbb431c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 3 Dec 2024 16:36:00 +0000 Subject: [PATCH 2/3] Add `Workspace` dependency to `swift-bootstrap/CMakeLists.txt` --- Sources/swift-bootstrap/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/swift-bootstrap/CMakeLists.txt b/Sources/swift-bootstrap/CMakeLists.txt index e89e47d2c73..98fcdb86e07 100644 --- a/Sources/swift-bootstrap/CMakeLists.txt +++ b/Sources/swift-bootstrap/CMakeLists.txt @@ -23,4 +23,5 @@ target_link_libraries(swift-bootstrap PRIVATE SwiftDriver TSCBasic TSCUtility + Workspace XCBuildSupport) From 7ec5851f95147c1648b92ae4bea4a233346bb20e Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 5 Dec 2024 17:26:48 +0000 Subject: [PATCH 3/3] Try linking `Commands` instead of `CoreCommands` --- Sources/swift-bootstrap/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/swift-bootstrap/CMakeLists.txt b/Sources/swift-bootstrap/CMakeLists.txt index 98fcdb86e07..4e940d2a3f2 100644 --- a/Sources/swift-bootstrap/CMakeLists.txt +++ b/Sources/swift-bootstrap/CMakeLists.txt @@ -16,12 +16,11 @@ target_link_libraries(swift-bootstrap PRIVATE ArgumentParser Basics Build - CoreCommands + Commands PackageGraph PackageLoading PackageModel SwiftDriver TSCBasic TSCUtility - Workspace XCBuildSupport)