From 2cd79dc6bdd8d9142d3afd3f1f8dfb529a1a23ba Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Tue, 11 Nov 2025 17:13:08 -0800 Subject: [PATCH 1/9] Use the correct build path suffix across all platforms Now it's correct everywhere, not only for macOS, Windows, and Linux. Main motivation was for FreeBSD, and will also work for Android, Wasm, iOS, etc. --- .../BuildParameters/BuildParameters.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index 4f45f7de9b2..e5d9802b79f 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -247,10 +247,14 @@ public struct BuildParameters: Encodable { switch buildSystemKind { case .xcode, .swiftbuild: var configDir: String = configuration.dirname.capitalized - if self.triple.isWindows() { - configDir += "-windows" - } else if self.triple.isLinux() { - configDir += "-linux" + if self.triple.isMacOSX { + // no suffix + } else if self.triple.isAndroid() { + configDir += "-android" + } else if self.triple.isWasm { + configDir += "-webassembly" + } else { + configDir += "-" + (self.triple.darwinPlatform?.platformName ?? self.triple.osNameUnversioned) } return dataPath.appending(components: "Products", configDir) case .native: From 2aa8df4b09f16d46ccce9a05625f16dc44f1e76c Mon Sep 17 00:00:00 2001 From: Dave Inglis Date: Thu, 13 Nov 2025 11:41:47 -0500 Subject: [PATCH 2/9] Revert "Optional xcframework support for Linux" (#9374) Reverts swiftlang/swift-package-manager#7239 Fails on some linux distros --- .../SwiftFramework/Package.swift | 16 --- .../SwiftFramework/SwiftFramework.swift | 8 -- .../TestBinary/Package.swift | 17 --- .../TestBinary/Sources/TestBinary/Main.swift | 3 - Sources/Build/BuildPlan/BuildPlan+Clang.swift | 6 +- .../Build/BuildPlan/BuildPlan+Product.swift | 3 +- Sources/Build/BuildPlan/BuildPlan+Swift.swift | 6 +- Sources/Build/BuildPlan/BuildPlan.swift | 7 +- Sources/CoreCommands/Options.swift | 7 -- Sources/CoreCommands/SwiftCommandState.swift | 1 - .../BinaryTarget+Extensions.swift | 13 +- .../BuildParameters/BuildParameters.swift | 5 - .../MockBuildTestHelper.swift | 7 +- .../MockBuildTestHelper.swift | 2 - Tests/BuildTests/BuildPlanTests.swift | 114 ------------------ .../LibraryEvolutionXCFLinuxTests.swift | 109 ----------------- 16 files changed, 12 insertions(+), 312 deletions(-) delete mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift delete mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift delete mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift delete mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift delete mode 100644 Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift deleted file mode 100644 index 70af89cbeeb..00000000000 --- a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift +++ /dev/null @@ -1,16 +0,0 @@ -// swift-tools-version:6.0 - -import PackageDescription - -let package = Package( - name: "SwiftFramework", - products: [ - .library(name: "SwiftFramework", type: .dynamic, targets: ["SwiftFramework"]), - ], - targets: [ - .target( - name: "SwiftFramework", - swiftSettings: [.unsafeFlags(["-enable-library-evolution"])] - ), - ] -) diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift deleted file mode 100644 index 5ad86872cd1..00000000000 --- a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift +++ /dev/null @@ -1,8 +0,0 @@ -public enum SwiftFrameworkWithEvolution -{ - case v1 - case v2 - - public - static var latest:Self { .v2 } -} \ No newline at end of file diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift deleted file mode 100644 index 4cbb13f39c2..00000000000 --- a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift +++ /dev/null @@ -1,17 +0,0 @@ -// swift-tools-version:6.0 - -import PackageDescription - -let package = Package(name: "TestBinary", - products: [ - .executable(name: "TestBinary", targets: ["TestBinary"]), - ], - targets: [ - .binaryTarget(name: "SwiftFramework", path: "SwiftFramework.xcframework"), - .executableTarget(name: "TestBinary", - dependencies: [ - .target(name: "SwiftFramework"), - ] - ), - ] -) \ No newline at end of file diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift deleted file mode 100644 index b088848fa17..00000000000 --- a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift +++ /dev/null @@ -1,3 +0,0 @@ -import SwiftFramework - -print("Latest Framework with LibraryEvolution version: \(SwiftFrameworkWithEvolution.latest)") \ No newline at end of file diff --git a/Sources/Build/BuildPlan/BuildPlan+Clang.swift b/Sources/Build/BuildPlan/BuildPlan+Clang.swift index 01306cdcf7d..fe9bc8f7619 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Clang.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Clang.swift @@ -65,11 +65,7 @@ extension BuildPlan { clangTarget.libraryBinaryPaths.insert(library.libraryPath) } case .xcframework: - let libraries = try self.parseXCFramework( - for: target, - triple: clangTarget.buildParameters.triple, - enableXCFrameworksOnLinux: clangTarget.buildParameters.enableXCFrameworksOnLinux - ) + let libraries = try self.parseXCFramework(for: target, triple: clangTarget.buildParameters.triple) for library in libraries { library.headersPaths.forEach { clangTarget.additionalFlags += ["-I", $0.pathString] diff --git a/Sources/Build/BuildPlan/BuildPlan+Product.swift b/Sources/Build/BuildPlan/BuildPlan+Product.swift index b290f9e3fd3..f7b1bb41231 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Product.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Product.swift @@ -298,8 +298,7 @@ extension BuildPlan { case .xcframework: let libraries = try self.parseXCFramework( for: binaryTarget, - triple: productDescription.buildParameters.triple, - enableXCFrameworksOnLinux: productDescription.buildParameters.enableXCFrameworksOnLinux + triple: productDescription.buildParameters.triple ) for library in libraries { libraryBinaryPaths.insert(library.libraryPath) diff --git a/Sources/Build/BuildPlan/BuildPlan+Swift.swift b/Sources/Build/BuildPlan/BuildPlan+Swift.swift index b5acf6149d1..9e16e02f0e0 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Swift.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Swift.swift @@ -61,11 +61,7 @@ extension BuildPlan { swiftTarget.libraryBinaryPaths.insert(library.libraryPath) } case .xcframework: - let libraries = try self.parseXCFramework( - for: target, - triple: swiftTarget.buildParameters.triple, - enableXCFrameworksOnLinux: swiftTarget.buildParameters.enableXCFrameworksOnLinux - ) + let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.buildParameters.triple) for library in libraries { library.headersPaths.forEach { swiftTarget.additionalFlags += ["-I", $0.pathString, "-Xcc", "-I", "-Xcc", $0.pathString] diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift index bef12b95fa8..b54f7b939c6 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -653,12 +653,9 @@ public class BuildPlan: SPMBuildCore.BuildPlan { } /// Extracts the library information from an XCFramework. - func parseXCFramework(for binaryTarget: BinaryModule, triple: Basics.Triple, enableXCFrameworksOnLinux: Bool) throws -> [LibraryInfo] { + func parseXCFramework(for binaryTarget: BinaryModule, triple: Basics.Triple) throws -> [LibraryInfo] { try self.externalLibrariesCache.memoize(key: binaryTarget) { - if !enableXCFrameworksOnLinux && triple.os == .linux { - return [] - } - return try binaryTarget.parseXCFrameworks(for: triple, fileSystem: self.fileSystem) + try binaryTarget.parseXCFrameworks(for: triple, fileSystem: self.fileSystem) } } diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index 3b7411d8ce9..ab0db1df264 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -515,13 +515,6 @@ public struct BuildOptions: ParsableArguments { @Flag(name: .customLong("experimental-prepare-for-indexing-no-lazy"), help: .hidden) var prepareForIndexingNoLazy: Bool = false - /// Hidden option to allow XCFrameworks on Linux - @Flag( - name: .customLong("experimental-xcframeworks-on-linux"), - help: .hidden - ) - public var enableXCFrameworksOnLinux: Bool = false - /// Whether to enable generation of `.swiftinterface`s alongside `.swiftmodule`s. @Flag(name: .customLong("enable-parseable-module-interfaces")) public var shouldEnableParseableModuleInterfaces: Bool = false diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index b4a6158274b..ceacbf39b79 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -941,7 +941,6 @@ public final class SwiftCommandState { sanitizers: options.build.enabledSanitizers, indexStoreMode: options.build.indexStoreMode.buildParameter, prepareForIndexing: prepareForIndexingMode, - enableXCFrameworksOnLinux: options.build.enableXCFrameworksOnLinux, debuggingParameters: .init( debugInfoFormat: self.options.build.debugInfoFormat.buildParameter, triple: triple, diff --git a/Sources/SPMBuildCore/BinaryTarget+Extensions.swift b/Sources/SPMBuildCore/BinaryTarget+Extensions.swift index d5286127a9e..902e51089c0 100644 --- a/Sources/SPMBuildCore/BinaryTarget+Extensions.swift +++ b/Sources/SPMBuildCore/BinaryTarget+Extensions.swift @@ -45,7 +45,7 @@ extension BinaryModule { let metadata = try XCFrameworkMetadata.parse(fileSystem: fileSystem, rootPath: self.artifactPath) // Filter the libraries that are relevant to the triple. guard let library = metadata.libraries.first(where: { - $0.platform == triple.asXCFrameworkPlatformString && + $0.platform == triple.os?.asXCFrameworkPlatformString && $0.variant == triple.environment?.asXCFrameworkPlatformVariantString && $0.architectures.contains(triple.archName) }) else { @@ -117,11 +117,13 @@ extension Triple { return self } } +} +extension Triple.OS { /// Returns a representation of the receiver that can be compared with platform strings declared in an XCFramework. fileprivate var asXCFrameworkPlatformString: String? { - switch self.os { - case .darwin, .wasi, .win32, .openbsd, .freebsd, .noneOS: + switch self { + case .darwin, .linux, .wasi, .win32, .openbsd, .freebsd, .noneOS: return nil // XCFrameworks do not support any of these platforms today. case .macosx: return "macos" @@ -131,11 +133,6 @@ extension Triple { return "tvos" case .watchos: return "watchos" - case .linux: - if environment == .android { - return nil - } - return "linux" // Only if --experimental-xcframeworks-on-linux has been passed default: return nil // XCFrameworks do not support any of these platforms today. } diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index e5d9802b79f..035f4911c41 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -132,9 +132,6 @@ public struct BuildParameters: Encodable { /// Do minimal build to prepare for indexing public var prepareForIndexing: PrepareForIndexingMode - /// Support Experimental XCF on Linux - public var enableXCFrameworksOnLinux: Bool - /// Build parameters related to debugging. public var debuggingParameters: Debugging @@ -169,7 +166,6 @@ public struct BuildParameters: Encodable { indexStoreMode: IndexStoreMode = .auto, shouldSkipBuilding: Bool = false, prepareForIndexing: PrepareForIndexingMode = .off, - enableXCFrameworksOnLinux: Bool = false, debuggingParameters: Debugging? = nil, driverParameters: Driver = .init(), linkingParameters: Linking = .init(), @@ -233,7 +229,6 @@ public struct BuildParameters: Encodable { self.indexStoreMode = indexStoreMode self.shouldSkipBuilding = shouldSkipBuilding self.prepareForIndexing = prepareForIndexing - self.enableXCFrameworksOnLinux = enableXCFrameworksOnLinux self.driverParameters = driverParameters self.linkingParameters = linkingParameters self.outputParameters = outputParameters diff --git a/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift b/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift index 8354b6e19ce..af0bfac2369 100644 --- a/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift +++ b/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift @@ -66,7 +66,6 @@ public func mockBuildPlan( commonFlags: PackageModel.BuildFlags = .init(), indexStoreMode: BuildParameters.IndexStoreMode = .off, omitFramePointers: Bool? = nil, - enableXCFrameworksOnLinux: Bool = false, driverParameters: BuildParameters.Driver = .init(), linkingParameters: BuildParameters.Linking = .init(), targetSanitizers: EnabledSanitizers = .init(), @@ -106,8 +105,7 @@ public func mockBuildPlan( toolchain: toolchain, flags: commonFlags, triple: inferredTriple, - indexStoreMode: indexStoreMode, - enableXCFrameworksOnLinux: enableXCFrameworksOnLinux + indexStoreMode: indexStoreMode ) destinationParameters.debuggingParameters = commonDebuggingParameters destinationParameters.driverParameters = driverParameters @@ -121,8 +119,7 @@ public func mockBuildPlan( toolchain: toolchain, flags: commonFlags, triple: inferredTriple, - indexStoreMode: indexStoreMode, - enableXCFrameworksOnLinux: enableXCFrameworksOnLinux + indexStoreMode: indexStoreMode ) hostParameters.debuggingParameters = commonDebuggingParameters hostParameters.driverParameters = driverParameters diff --git a/Sources/_InternalTestSupport/MockBuildTestHelper.swift b/Sources/_InternalTestSupport/MockBuildTestHelper.swift index 024726107c9..78820551777 100644 --- a/Sources/_InternalTestSupport/MockBuildTestHelper.swift +++ b/Sources/_InternalTestSupport/MockBuildTestHelper.swift @@ -91,7 +91,6 @@ public func mockBuildParameters( linkerDeadStrip: Bool = true, linkTimeOptimizationMode: BuildParameters.LinkTimeOptimizationMode? = nil, omitFramePointers: Bool? = nil, - enableXCFrameworksOnLinux: Bool = false, prepareForIndexing: BuildParameters.PrepareForIndexingMode = .off ) -> BuildParameters { try! BuildParameters( @@ -106,7 +105,6 @@ public func mockBuildParameters( workers: 3, indexStoreMode: indexStoreMode, prepareForIndexing: prepareForIndexing, - enableXCFrameworksOnLinux: enableXCFrameworksOnLinux, debuggingParameters: .init( triple: triple, shouldEnableDebuggingEntitlement: config == .debug, diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 62abd5aa3db..c0f61204e73 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -6807,114 +6807,6 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { XCTAssertMatch(dynamicLibraryPathExtension, "dylib") } - func testXCFrameworkBinaryTargetsLinux(platform: String = "linux", arch: String, targetTriple: Basics.Triple) async throws { - let Pkg: AbsolutePath = "/Pkg" - - let fs = InMemoryFileSystem( - emptyFiles: - Pkg.appending(components: "Sources", "exe", "main.swift").pathString, - Pkg.appending(components: "Sources", "Library", "Library.swift").pathString - ) - - try fs.createDirectory("/Pkg/Framework.xcframework", recursive: true) - try fs.writeFileContents( - "/Pkg/Framework.xcframework/Info.plist", - string: """ - - - - - AvailableLibraries - - - LibraryIdentifier - \(platform)-\(arch) - LibraryPath - Framework.framework - SupportedArchitectures - - \(arch) - - SupportedPlatform - \(platform) - - - CFBundlePackageType - XFWK - XCFrameworkFormatVersion - 1.0 - - - """ - ) - - let observability = ObservabilitySystem.makeForTesting() - - let graph = try loadModulesGraph( - fileSystem: fs, - manifests: [ - Manifest.createRootManifest( - displayName: "Pkg", - path: .init(validating: Pkg.pathString), - products: [ - ProductDescription(name: "exe", type: .executable, targets: ["exe"]), - ProductDescription(name: "Library", type: .library(.dynamic), targets: ["Library"]), - ], - targets: [ - TargetDescription(name: "exe", dependencies: ["Library"]), - TargetDescription(name: "Library", dependencies: ["Framework"]), - TargetDescription(name: "Framework", path: "Framework.xcframework", type: .binary), - ] - ), - ], - binaryArtifacts: [ - .plain("pkg"): [ - "Framework": .init(kind: .xcframework, originURL: nil, path: "/Pkg/Framework.xcframework"), - ], - ], - observabilityScope: observability.topScope - ) - XCTAssertNoDiagnostics(observability.diagnostics) - - let result = try await BuildPlanResult(plan: mockBuildPlan( - triple: targetTriple, - graph: graph, - enableXCFrameworksOnLinux: true, - fileSystem: fs, - observabilityScope: observability.topScope - )) - XCTAssertNoDiagnostics(observability.diagnostics) - - result.checkProductsCount(2) - result.checkTargetsCount(2) - - let buildPath = result.plan.productsBuildPath - - let libraryBasicArguments = try result.moduleBuildDescription(for: "Library").swift().compileArguments() - XCTAssertMatch( - libraryBasicArguments, - [.anySequence, "-I", "\(Pkg.appending(components: "Framework.xcframework", "\(platform)-\(arch)"))", .anySequence] - ) - - let libraryLinkArguments = try result.buildProduct(for: "Library").linkArguments() - XCTAssertMatch(libraryLinkArguments, [.anySequence, "-L", "\(buildPath)", .anySequence]) - - let exeCompileArguments = try result.moduleBuildDescription(for: "exe").swift().compileArguments() - XCTAssertMatch( - exeCompileArguments, - [.anySequence, "-I", "\(Pkg.appending(components: "Framework.xcframework", "\(platform)-\(arch)"))", .anySequence] - ) - - let exeLinkArguments = try result.buildProduct(for: "exe").linkArguments() - XCTAssertMatch(exeLinkArguments, [.anySequence, "-L", "\(buildPath)", .anySequence]) - - let executablePathExtension = try result.buildProduct(for: "exe").binaryPath.extension ?? "" - XCTAssertMatch(executablePathExtension, "") - - let dynamicLibraryPathExtension = try result.buildProduct(for: "Library").binaryPath.extension - XCTAssertMatch(dynamicLibraryPathExtension, "so") - } - func testXCFrameworkBinaryTargets() async throws { try await self.testXCFrameworkBinaryTargets(platform: "macos", arch: "x86_64", targetTriple: .x86_64MacOS) @@ -6923,12 +6815,6 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { let arm64eTriple = try Basics.Triple("arm64e-apple-macosx") try await self.testXCFrameworkBinaryTargets(platform: "macos", arch: "arm64e", targetTriple: arm64eTriple) - - let x86_64Linux = try Basics.Triple("x86_64-unknown-linux-gnu") - try await self.testXCFrameworkBinaryTargetsLinux(arch: "x86_64", targetTriple: x86_64Linux) - - let aarch64Linux = try Basics.Triple("aarch64-unknown-linux-gnu") - try await self.testXCFrameworkBinaryTargetsLinux(arch: "aarch64", targetTriple: aarch64Linux) } func testArtifactsArchiveBinaryTargets( diff --git a/Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift b/Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift deleted file mode 100644 index 54e21ca73ab..00000000000 --- a/Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift +++ /dev/null @@ -1,109 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 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 _InternalTestSupport -import Basics -import Testing - -private struct SwiftPMTests { - @Test( - .requireSwift6_2, - .requireHostOS(.linux) - ) - func libraryEvolutionLinuxXCFramework() async throws { - try await fixture(name: "Miscellaneous/LibraryEvolutionLinuxXCF") { fixturePath in - let swiftFramework = "SwiftFramework" - try await withTemporaryDirectory(removeTreeOnDeinit: false) { tmpDir in - let scratchPath = tmpDir.appending(component: ".build") - try await executeSwiftBuild( - fixturePath.appending(component: swiftFramework), - configuration: .debug, - extraArgs: ["--scratch-path", scratchPath.pathString], - buildSystem: .native - ) - - #if arch(arm64) - let arch = "arm64" - #elseif arch(x86_64) - let arch = "x86_64" - #endif - - let platform = "linux" - let libraryExtension = "so" - - let xcframeworkPath = fixturePath.appending( - components: "TestBinary", - "\(swiftFramework).xcframework" - ) - let libraryName = "lib\(swiftFramework).\(libraryExtension)" - let artifactsPath = xcframeworkPath.appending(component: "\(platform)-\(arch)") - - try localFileSystem.createDirectory(artifactsPath, recursive: true) - - try localFileSystem.copy( - from: scratchPath.appending(components: "debug", libraryName), - to: artifactsPath.appending(component: libraryName) - ) - - try localFileSystem.copy( - from: scratchPath.appending(components: "debug", "Modules", "\(swiftFramework).swiftinterface"), - to: artifactsPath.appending(component: "\(swiftFramework).swiftinterface") - ) - - try localFileSystem.writeFileContents( - xcframeworkPath.appending(component: "Info.plist"), - string: """ - - - - - AvailableLibraries - - - BinaryPath - \(libraryName) - LibraryIdentifier - \(platform)-\(arch) - LibraryPath - \(libraryName) - SupportedArchitectures - - \(arch) - - SupportedPlatform - \(platform) - - - CFBundlePackageType - XFWK - XCFrameworkFormatVersion - 1.0 - - - """ - ) - } - - let packagePath = fixturePath.appending(component: "TestBinary") - let scratchPath = packagePath.appending(component: ".build-test") - let runOutput = try await executeSwiftRun( - packagePath, "TestBinary", - extraArgs: [ - "--scratch-path", scratchPath.pathString, "--experimental-xcframeworks-on-linux", - ], - buildSystem: .native - ) - #expect(!runOutput.stderr.contains("error:")) - #expect(runOutput.stdout.contains("Latest Framework with LibraryEvolution version: v2")) - } - } -} \ No newline at end of file From 497944d0de34826f8ac2cff5cee76d4ba997059a Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 13 Nov 2025 17:23:41 -0500 Subject: [PATCH 3/9] Add experimental max parallelization width option for Swift Testing. (#9361) Adds `swift test --experimental-maximum-parallelization-width`. This flag passes through to Swift Testing. We may end up just reusing `--num-workers` but as it's not exactly the same feature, I'm keeping it separate for now pending discussion and review. --- Sources/Commands/SwiftTestCommand.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index d2eefa5fd97..10c3b280c29 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -162,6 +162,12 @@ struct TestCommandOptions: ParsableArguments { help: "Number of tests to execute in parallel.") var numberOfWorkers: Int? + /// Width of task group used by Swift Testing. + /// + /// This argument is consumed by Swift Testing and is passed through verbatim by SwiftPM. + @Option(help: .hidden) + var experimentalMaximumParallelizationWidth: Int? = nil + /// List the tests and exit. @Flag(name: [.customLong("list-tests"), .customShort("l")], help: "Lists test methods in specifier format.") From 7ad4f831e3831070bc1425e28d806a5c89ceccaf Mon Sep 17 00:00:00 2001 From: vsarunas <3808892+vsarunas@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:19:09 +0100 Subject: [PATCH 4/9] Optional xcframework support for Linux (#9375) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-apply https://github.com/swiftlang/swift-package-manager/pull/9374 which reverts https://github.com/swiftlang/swift-package-manager/pull/7239. Fix Linux arm build; replacing arm64 -> aarch64; Ubuntu test passes. Fixes https://github.com/swiftlang/swift-package-manager/issues/9372 Prior it was failing with: ``` swift-package-manager/.build/aarch64-unknown-linux-gnu/debug/swift-run --package-path /tmp/Miscellaneous_LibraryEvolutionLinuxXCF.07p2Rv/TestBinary --configuration debug --build-system native --scratch-path /tmp/Miscellaneous_LibraryEvolutionLinuxXCF.07p2Rv/TestBinary/.build-test --experimental-xcframeworks-on-linux TestBinary output: Building for debugging... [0/5] Write sources [1/5] Write swift-version--1B491C3C2A126B95.txt error: emit-module command failed with exit code 1 (use -v to see invocation) [3/7] Emitting module TestBinary /tmp/Miscellaneous_LibraryEvolutionLinuxXCF.07p2Rv/TestBinary/Sources/TestBinary/Main.swift:1:8: error: no such module 'SwiftFramework' 1 | import SwiftFramework | `- error: no such module 'SwiftFramework' 2 | 3 | print("Latest Framework with LibraryEvolution version: \(SwiftFrameworkWithEvolution.latest)") [4/7] Compiling TestBinary Main.swift /tmp/Miscellaneous_LibraryEvolutionLinuxXCF.07p2Rv/TestBinary/Sources/TestBinary/Main.swift:1:8: error: no such module 'SwiftFramework' 1 | import SwiftFramework | `- error: no such module 'SwiftFramework' 2 | 3 | print("Latest Framework with LibraryEvolution version: \(SwiftFrameworkWithEvolution.latest)") ✘ Test libraryEvolutionLinuxXCFramework() failed after 2.350 seconds with 1 issue. ``` --- .../SwiftFramework/Package.swift | 16 +++ .../SwiftFramework/SwiftFramework.swift | 8 ++ .../TestBinary/Package.swift | 17 +++ .../TestBinary/Sources/TestBinary/Main.swift | 3 + Sources/Build/BuildPlan/BuildPlan+Clang.swift | 6 +- .../Build/BuildPlan/BuildPlan+Product.swift | 3 +- Sources/Build/BuildPlan/BuildPlan+Swift.swift | 6 +- Sources/Build/BuildPlan/BuildPlan.swift | 7 +- Sources/CoreCommands/Options.swift | 7 ++ Sources/CoreCommands/SwiftCommandState.swift | 1 + .../BinaryTarget+Extensions.swift | 13 +- .../BuildParameters/BuildParameters.swift | 5 + .../MockBuildTestHelper.swift | 7 +- .../MockBuildTestHelper.swift | 2 + Tests/BuildTests/BuildPlanTests.swift | 114 ++++++++++++++++++ .../LibraryEvolutionXCFLinuxTests.swift | 109 +++++++++++++++++ 16 files changed, 312 insertions(+), 12 deletions(-) create mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift create mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift create mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift create mode 100644 Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift create mode 100644 Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift new file mode 100644 index 00000000000..70af89cbeeb --- /dev/null +++ b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift @@ -0,0 +1,16 @@ +// swift-tools-version:6.0 + +import PackageDescription + +let package = Package( + name: "SwiftFramework", + products: [ + .library(name: "SwiftFramework", type: .dynamic, targets: ["SwiftFramework"]), + ], + targets: [ + .target( + name: "SwiftFramework", + swiftSettings: [.unsafeFlags(["-enable-library-evolution"])] + ), + ] +) diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift new file mode 100644 index 00000000000..5ad86872cd1 --- /dev/null +++ b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift @@ -0,0 +1,8 @@ +public enum SwiftFrameworkWithEvolution +{ + case v1 + case v2 + + public + static var latest:Self { .v2 } +} \ No newline at end of file diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift new file mode 100644 index 00000000000..4cbb13f39c2 --- /dev/null +++ b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift @@ -0,0 +1,17 @@ +// swift-tools-version:6.0 + +import PackageDescription + +let package = Package(name: "TestBinary", + products: [ + .executable(name: "TestBinary", targets: ["TestBinary"]), + ], + targets: [ + .binaryTarget(name: "SwiftFramework", path: "SwiftFramework.xcframework"), + .executableTarget(name: "TestBinary", + dependencies: [ + .target(name: "SwiftFramework"), + ] + ), + ] +) \ No newline at end of file diff --git a/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift new file mode 100644 index 00000000000..b088848fa17 --- /dev/null +++ b/Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift @@ -0,0 +1,3 @@ +import SwiftFramework + +print("Latest Framework with LibraryEvolution version: \(SwiftFrameworkWithEvolution.latest)") \ No newline at end of file diff --git a/Sources/Build/BuildPlan/BuildPlan+Clang.swift b/Sources/Build/BuildPlan/BuildPlan+Clang.swift index fe9bc8f7619..01306cdcf7d 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Clang.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Clang.swift @@ -65,7 +65,11 @@ extension BuildPlan { clangTarget.libraryBinaryPaths.insert(library.libraryPath) } case .xcframework: - let libraries = try self.parseXCFramework(for: target, triple: clangTarget.buildParameters.triple) + let libraries = try self.parseXCFramework( + for: target, + triple: clangTarget.buildParameters.triple, + enableXCFrameworksOnLinux: clangTarget.buildParameters.enableXCFrameworksOnLinux + ) for library in libraries { library.headersPaths.forEach { clangTarget.additionalFlags += ["-I", $0.pathString] diff --git a/Sources/Build/BuildPlan/BuildPlan+Product.swift b/Sources/Build/BuildPlan/BuildPlan+Product.swift index f7b1bb41231..b290f9e3fd3 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Product.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Product.swift @@ -298,7 +298,8 @@ extension BuildPlan { case .xcframework: let libraries = try self.parseXCFramework( for: binaryTarget, - triple: productDescription.buildParameters.triple + triple: productDescription.buildParameters.triple, + enableXCFrameworksOnLinux: productDescription.buildParameters.enableXCFrameworksOnLinux ) for library in libraries { libraryBinaryPaths.insert(library.libraryPath) diff --git a/Sources/Build/BuildPlan/BuildPlan+Swift.swift b/Sources/Build/BuildPlan/BuildPlan+Swift.swift index 9e16e02f0e0..b5acf6149d1 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Swift.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Swift.swift @@ -61,7 +61,11 @@ extension BuildPlan { swiftTarget.libraryBinaryPaths.insert(library.libraryPath) } case .xcframework: - let libraries = try self.parseXCFramework(for: target, triple: swiftTarget.buildParameters.triple) + let libraries = try self.parseXCFramework( + for: target, + triple: swiftTarget.buildParameters.triple, + enableXCFrameworksOnLinux: swiftTarget.buildParameters.enableXCFrameworksOnLinux + ) for library in libraries { library.headersPaths.forEach { swiftTarget.additionalFlags += ["-I", $0.pathString, "-Xcc", "-I", "-Xcc", $0.pathString] diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift index b54f7b939c6..bef12b95fa8 100644 --- a/Sources/Build/BuildPlan/BuildPlan.swift +++ b/Sources/Build/BuildPlan/BuildPlan.swift @@ -653,9 +653,12 @@ public class BuildPlan: SPMBuildCore.BuildPlan { } /// Extracts the library information from an XCFramework. - func parseXCFramework(for binaryTarget: BinaryModule, triple: Basics.Triple) throws -> [LibraryInfo] { + func parseXCFramework(for binaryTarget: BinaryModule, triple: Basics.Triple, enableXCFrameworksOnLinux: Bool) throws -> [LibraryInfo] { try self.externalLibrariesCache.memoize(key: binaryTarget) { - try binaryTarget.parseXCFrameworks(for: triple, fileSystem: self.fileSystem) + if !enableXCFrameworksOnLinux && triple.os == .linux { + return [] + } + return try binaryTarget.parseXCFrameworks(for: triple, fileSystem: self.fileSystem) } } diff --git a/Sources/CoreCommands/Options.swift b/Sources/CoreCommands/Options.swift index ab0db1df264..3b7411d8ce9 100644 --- a/Sources/CoreCommands/Options.swift +++ b/Sources/CoreCommands/Options.swift @@ -515,6 +515,13 @@ public struct BuildOptions: ParsableArguments { @Flag(name: .customLong("experimental-prepare-for-indexing-no-lazy"), help: .hidden) var prepareForIndexingNoLazy: Bool = false + /// Hidden option to allow XCFrameworks on Linux + @Flag( + name: .customLong("experimental-xcframeworks-on-linux"), + help: .hidden + ) + public var enableXCFrameworksOnLinux: Bool = false + /// Whether to enable generation of `.swiftinterface`s alongside `.swiftmodule`s. @Flag(name: .customLong("enable-parseable-module-interfaces")) public var shouldEnableParseableModuleInterfaces: Bool = false diff --git a/Sources/CoreCommands/SwiftCommandState.swift b/Sources/CoreCommands/SwiftCommandState.swift index ceacbf39b79..b4a6158274b 100644 --- a/Sources/CoreCommands/SwiftCommandState.swift +++ b/Sources/CoreCommands/SwiftCommandState.swift @@ -941,6 +941,7 @@ public final class SwiftCommandState { sanitizers: options.build.enabledSanitizers, indexStoreMode: options.build.indexStoreMode.buildParameter, prepareForIndexing: prepareForIndexingMode, + enableXCFrameworksOnLinux: options.build.enableXCFrameworksOnLinux, debuggingParameters: .init( debugInfoFormat: self.options.build.debugInfoFormat.buildParameter, triple: triple, diff --git a/Sources/SPMBuildCore/BinaryTarget+Extensions.swift b/Sources/SPMBuildCore/BinaryTarget+Extensions.swift index 902e51089c0..d5286127a9e 100644 --- a/Sources/SPMBuildCore/BinaryTarget+Extensions.swift +++ b/Sources/SPMBuildCore/BinaryTarget+Extensions.swift @@ -45,7 +45,7 @@ extension BinaryModule { let metadata = try XCFrameworkMetadata.parse(fileSystem: fileSystem, rootPath: self.artifactPath) // Filter the libraries that are relevant to the triple. guard let library = metadata.libraries.first(where: { - $0.platform == triple.os?.asXCFrameworkPlatformString && + $0.platform == triple.asXCFrameworkPlatformString && $0.variant == triple.environment?.asXCFrameworkPlatformVariantString && $0.architectures.contains(triple.archName) }) else { @@ -117,13 +117,11 @@ extension Triple { return self } } -} -extension Triple.OS { /// Returns a representation of the receiver that can be compared with platform strings declared in an XCFramework. fileprivate var asXCFrameworkPlatformString: String? { - switch self { - case .darwin, .linux, .wasi, .win32, .openbsd, .freebsd, .noneOS: + switch self.os { + case .darwin, .wasi, .win32, .openbsd, .freebsd, .noneOS: return nil // XCFrameworks do not support any of these platforms today. case .macosx: return "macos" @@ -133,6 +131,11 @@ extension Triple.OS { return "tvos" case .watchos: return "watchos" + case .linux: + if environment == .android { + return nil + } + return "linux" // Only if --experimental-xcframeworks-on-linux has been passed default: return nil // XCFrameworks do not support any of these platforms today. } diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index 035f4911c41..e5d9802b79f 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -132,6 +132,9 @@ public struct BuildParameters: Encodable { /// Do minimal build to prepare for indexing public var prepareForIndexing: PrepareForIndexingMode + /// Support Experimental XCF on Linux + public var enableXCFrameworksOnLinux: Bool + /// Build parameters related to debugging. public var debuggingParameters: Debugging @@ -166,6 +169,7 @@ public struct BuildParameters: Encodable { indexStoreMode: IndexStoreMode = .auto, shouldSkipBuilding: Bool = false, prepareForIndexing: PrepareForIndexingMode = .off, + enableXCFrameworksOnLinux: Bool = false, debuggingParameters: Debugging? = nil, driverParameters: Driver = .init(), linkingParameters: Linking = .init(), @@ -229,6 +233,7 @@ public struct BuildParameters: Encodable { self.indexStoreMode = indexStoreMode self.shouldSkipBuilding = shouldSkipBuilding self.prepareForIndexing = prepareForIndexing + self.enableXCFrameworksOnLinux = enableXCFrameworksOnLinux self.driverParameters = driverParameters self.linkingParameters = linkingParameters self.outputParameters = outputParameters diff --git a/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift b/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift index af0bfac2369..8354b6e19ce 100644 --- a/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift +++ b/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift @@ -66,6 +66,7 @@ public func mockBuildPlan( commonFlags: PackageModel.BuildFlags = .init(), indexStoreMode: BuildParameters.IndexStoreMode = .off, omitFramePointers: Bool? = nil, + enableXCFrameworksOnLinux: Bool = false, driverParameters: BuildParameters.Driver = .init(), linkingParameters: BuildParameters.Linking = .init(), targetSanitizers: EnabledSanitizers = .init(), @@ -105,7 +106,8 @@ public func mockBuildPlan( toolchain: toolchain, flags: commonFlags, triple: inferredTriple, - indexStoreMode: indexStoreMode + indexStoreMode: indexStoreMode, + enableXCFrameworksOnLinux: enableXCFrameworksOnLinux ) destinationParameters.debuggingParameters = commonDebuggingParameters destinationParameters.driverParameters = driverParameters @@ -119,7 +121,8 @@ public func mockBuildPlan( toolchain: toolchain, flags: commonFlags, triple: inferredTriple, - indexStoreMode: indexStoreMode + indexStoreMode: indexStoreMode, + enableXCFrameworksOnLinux: enableXCFrameworksOnLinux ) hostParameters.debuggingParameters = commonDebuggingParameters hostParameters.driverParameters = driverParameters diff --git a/Sources/_InternalTestSupport/MockBuildTestHelper.swift b/Sources/_InternalTestSupport/MockBuildTestHelper.swift index 78820551777..024726107c9 100644 --- a/Sources/_InternalTestSupport/MockBuildTestHelper.swift +++ b/Sources/_InternalTestSupport/MockBuildTestHelper.swift @@ -91,6 +91,7 @@ public func mockBuildParameters( linkerDeadStrip: Bool = true, linkTimeOptimizationMode: BuildParameters.LinkTimeOptimizationMode? = nil, omitFramePointers: Bool? = nil, + enableXCFrameworksOnLinux: Bool = false, prepareForIndexing: BuildParameters.PrepareForIndexingMode = .off ) -> BuildParameters { try! BuildParameters( @@ -105,6 +106,7 @@ public func mockBuildParameters( workers: 3, indexStoreMode: indexStoreMode, prepareForIndexing: prepareForIndexing, + enableXCFrameworksOnLinux: enableXCFrameworksOnLinux, debuggingParameters: .init( triple: triple, shouldEnableDebuggingEntitlement: config == .debug, diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index c0f61204e73..62abd5aa3db 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -6807,6 +6807,114 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { XCTAssertMatch(dynamicLibraryPathExtension, "dylib") } + func testXCFrameworkBinaryTargetsLinux(platform: String = "linux", arch: String, targetTriple: Basics.Triple) async throws { + let Pkg: AbsolutePath = "/Pkg" + + let fs = InMemoryFileSystem( + emptyFiles: + Pkg.appending(components: "Sources", "exe", "main.swift").pathString, + Pkg.appending(components: "Sources", "Library", "Library.swift").pathString + ) + + try fs.createDirectory("/Pkg/Framework.xcframework", recursive: true) + try fs.writeFileContents( + "/Pkg/Framework.xcframework/Info.plist", + string: """ + + + + + AvailableLibraries + + + LibraryIdentifier + \(platform)-\(arch) + LibraryPath + Framework.framework + SupportedArchitectures + + \(arch) + + SupportedPlatform + \(platform) + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + + """ + ) + + let observability = ObservabilitySystem.makeForTesting() + + let graph = try loadModulesGraph( + fileSystem: fs, + manifests: [ + Manifest.createRootManifest( + displayName: "Pkg", + path: .init(validating: Pkg.pathString), + products: [ + ProductDescription(name: "exe", type: .executable, targets: ["exe"]), + ProductDescription(name: "Library", type: .library(.dynamic), targets: ["Library"]), + ], + targets: [ + TargetDescription(name: "exe", dependencies: ["Library"]), + TargetDescription(name: "Library", dependencies: ["Framework"]), + TargetDescription(name: "Framework", path: "Framework.xcframework", type: .binary), + ] + ), + ], + binaryArtifacts: [ + .plain("pkg"): [ + "Framework": .init(kind: .xcframework, originURL: nil, path: "/Pkg/Framework.xcframework"), + ], + ], + observabilityScope: observability.topScope + ) + XCTAssertNoDiagnostics(observability.diagnostics) + + let result = try await BuildPlanResult(plan: mockBuildPlan( + triple: targetTriple, + graph: graph, + enableXCFrameworksOnLinux: true, + fileSystem: fs, + observabilityScope: observability.topScope + )) + XCTAssertNoDiagnostics(observability.diagnostics) + + result.checkProductsCount(2) + result.checkTargetsCount(2) + + let buildPath = result.plan.productsBuildPath + + let libraryBasicArguments = try result.moduleBuildDescription(for: "Library").swift().compileArguments() + XCTAssertMatch( + libraryBasicArguments, + [.anySequence, "-I", "\(Pkg.appending(components: "Framework.xcframework", "\(platform)-\(arch)"))", .anySequence] + ) + + let libraryLinkArguments = try result.buildProduct(for: "Library").linkArguments() + XCTAssertMatch(libraryLinkArguments, [.anySequence, "-L", "\(buildPath)", .anySequence]) + + let exeCompileArguments = try result.moduleBuildDescription(for: "exe").swift().compileArguments() + XCTAssertMatch( + exeCompileArguments, + [.anySequence, "-I", "\(Pkg.appending(components: "Framework.xcframework", "\(platform)-\(arch)"))", .anySequence] + ) + + let exeLinkArguments = try result.buildProduct(for: "exe").linkArguments() + XCTAssertMatch(exeLinkArguments, [.anySequence, "-L", "\(buildPath)", .anySequence]) + + let executablePathExtension = try result.buildProduct(for: "exe").binaryPath.extension ?? "" + XCTAssertMatch(executablePathExtension, "") + + let dynamicLibraryPathExtension = try result.buildProduct(for: "Library").binaryPath.extension + XCTAssertMatch(dynamicLibraryPathExtension, "so") + } + func testXCFrameworkBinaryTargets() async throws { try await self.testXCFrameworkBinaryTargets(platform: "macos", arch: "x86_64", targetTriple: .x86_64MacOS) @@ -6815,6 +6923,12 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { let arm64eTriple = try Basics.Triple("arm64e-apple-macosx") try await self.testXCFrameworkBinaryTargets(platform: "macos", arch: "arm64e", targetTriple: arm64eTriple) + + let x86_64Linux = try Basics.Triple("x86_64-unknown-linux-gnu") + try await self.testXCFrameworkBinaryTargetsLinux(arch: "x86_64", targetTriple: x86_64Linux) + + let aarch64Linux = try Basics.Triple("aarch64-unknown-linux-gnu") + try await self.testXCFrameworkBinaryTargetsLinux(arch: "aarch64", targetTriple: aarch64Linux) } func testArtifactsArchiveBinaryTargets( diff --git a/Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift b/Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift new file mode 100644 index 00000000000..b441c1a83f9 --- /dev/null +++ b/Tests/FunctionalTests/LibraryEvolutionXCFLinuxTests.swift @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 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 _InternalTestSupport +import Basics +import Testing + +private struct SwiftPMTests { + @Test( + .requireSwift6_2, + .requireHostOS(.linux) + ) + func libraryEvolutionLinuxXCFramework() async throws { + try await fixture(name: "Miscellaneous/LibraryEvolutionLinuxXCF") { fixturePath in + let swiftFramework = "SwiftFramework" + try await withTemporaryDirectory(removeTreeOnDeinit: false) { tmpDir in + let scratchPath = tmpDir.appending(component: ".build") + try await executeSwiftBuild( + fixturePath.appending(component: swiftFramework), + configuration: .debug, + extraArgs: ["--scratch-path", scratchPath.pathString], + buildSystem: .native + ) + + #if arch(arm64) + let arch = "aarch64" + #elseif arch(x86_64) + let arch = "x86_64" + #endif + + let platform = "linux" + let libraryExtension = "so" + + let xcframeworkPath = fixturePath.appending( + components: "TestBinary", + "\(swiftFramework).xcframework" + ) + let libraryName = "lib\(swiftFramework).\(libraryExtension)" + let artifactsPath = xcframeworkPath.appending(component: "\(platform)-\(arch)") + + try localFileSystem.createDirectory(artifactsPath, recursive: true) + + try localFileSystem.copy( + from: scratchPath.appending(components: "debug", libraryName), + to: artifactsPath.appending(component: libraryName) + ) + + try localFileSystem.copy( + from: scratchPath.appending(components: "debug", "Modules", "\(swiftFramework).swiftinterface"), + to: artifactsPath.appending(component: "\(swiftFramework).swiftinterface") + ) + + try localFileSystem.writeFileContents( + xcframeworkPath.appending(component: "Info.plist"), + string: """ + + + + + AvailableLibraries + + + BinaryPath + \(libraryName) + LibraryIdentifier + \(platform)-\(arch) + LibraryPath + \(libraryName) + SupportedArchitectures + + \(arch) + + SupportedPlatform + \(platform) + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + + """ + ) + } + + let packagePath = fixturePath.appending(component: "TestBinary") + let scratchPath = packagePath.appending(component: ".build-test") + let runOutput = try await executeSwiftRun( + packagePath, "TestBinary", + extraArgs: [ + "--scratch-path", scratchPath.pathString, "--experimental-xcframeworks-on-linux", + ], + buildSystem: .native + ) + #expect(!runOutput.stderr.contains("error:")) + #expect(runOutput.stdout.contains("Latest Framework with LibraryEvolution version: v2")) + } + } +} From a5a83d115cae6a9f67088effe39a32b5eb6b7fda Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Mon, 17 Nov 2025 00:31:51 -0800 Subject: [PATCH 5/9] bootstrap - add swift-tools-protocols (#9371) Swift Build and SwiftPM will adopt this package soon, but first we need to stage it in as a dependency of the bootstrap build --- CMakeLists.txt | 1 + Utilities/bootstrap | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3ba564143c..77450bf2961 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ if(FIND_PM_DEPS) find_package(SwiftASN1 CONFIG REQUIRED) find_package(SwiftCertificates CONFIG REQUIRED) find_package(SwiftCrypto CONFIG REQUIRED) + find_package(SwiftToolsProtocols CONFIG REQUIRED) find_package(SwiftBuild CONFIG REQUIRED) endif() diff --git a/Utilities/bootstrap b/Utilities/bootstrap index 5072f22eb9d..14219d6374b 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -244,6 +244,7 @@ def parse_global_args(args): args.source_dirs["swift-driver"] = os.path.join(args.project_root, "..", "swift-driver") args.source_dirs["swift-system"] = os.path.join(args.project_root, "..", "swift-system") args.source_dirs["swift-collections"] = os.path.join(args.project_root, "..", "swift-collections") + args.source_dirs["swift-tools-protocols"] = os.path.join(args.project_root, "..", "swift-tools-protocols") args.source_dirs["swift-certificates"] = os.path.join(args.project_root, "..", "swift-certificates") args.source_dirs["swift-asn1"] = os.path.join(args.project_root, "..", "swift-asn1") args.source_dirs["swift-syntax"] = os.path.join(args.project_root, "..", "swift-syntax") @@ -441,6 +442,7 @@ def build(args): ] build_dependency(args, "swift-driver", swift_driver_cmake_flags) build_dependency(args, "swift-collections") + build_dependency(args, "swift-tools-protocols") build_dependency(args, "swift-asn1") build_dependency(args, "swift-crypto", ["-DSwiftASN1_DIR=" + os.path.join(args.build_dirs["swift-asn1"], "cmake/modules")]) @@ -455,6 +457,7 @@ def build(args): "-DTSC_DIR=" + os.path.join(args.build_dirs["tsc"], "cmake/modules"), "-DArgumentParser_DIR=" + os.path.join(args.build_dirs["swift-argument-parser"], "cmake/modules"), "-DSwiftDriver_DIR=" + os.path.join(args.build_dirs["swift-driver"], "cmake/modules"), + "-DSwiftToolsProtocols_DIR=" + os.path.join(args.build_dirs["swift-tools-protocols"], "cmake/modules"), ] build_dependency(args, "swift-build", swift_build_cmake_flags) build_swiftpm_with_cmake(args) @@ -732,15 +735,16 @@ def build_swiftpm_with_cmake(args): cmake_flags = [ get_llbuild_cmake_arg(args), - "-DTSC_DIR=" + os.path.join(args.build_dirs["tsc"], "cmake/modules"), - "-DArgumentParser_DIR=" + os.path.join(args.build_dirs["swift-argument-parser"], "cmake/modules"), - "-DSwiftDriver_DIR=" + os.path.join(args.build_dirs["swift-driver"], "cmake/modules"), - "-DSwiftSystem_DIR=" + os.path.join(args.build_dirs["swift-system"], "cmake/modules"), - "-DSwiftCollections_DIR=" + os.path.join(args.build_dirs["swift-collections"], "cmake/modules"), - "-DSwiftCrypto_DIR=" + os.path.join(args.build_dirs["swift-crypto"], "cmake/modules"), - "-DSwiftASN1_DIR=" + os.path.join(args.build_dirs["swift-asn1"], "cmake/modules"), - "-DSwiftCertificates_DIR=" + os.path.join(args.build_dirs["swift-certificates"], "cmake/modules"), - "-DSwiftBuild_DIR=" + os.path.join(args.build_dirs["swift-build"], "cmake/modules"), + "-DTSC_DIR=" + os.path.join(args.build_dirs["tsc"], "cmake/modules"), + "-DArgumentParser_DIR=" + os.path.join(args.build_dirs["swift-argument-parser"], "cmake/modules"), + "-DSwiftToolsProtocols_DIR=" + os.path.join(args.build_dirs["swift-tools-protocols"], "cmake/modules"), + "-DSwiftDriver_DIR=" + os.path.join(args.build_dirs["swift-driver"], "cmake/modules"), + "-DSwiftSystem_DIR=" + os.path.join(args.build_dirs["swift-system"], "cmake/modules"), + "-DSwiftCollections_DIR=" + os.path.join(args.build_dirs["swift-collections"], "cmake/modules"), + "-DSwiftCrypto_DIR=" + os.path.join(args.build_dirs["swift-crypto"], "cmake/modules"), + "-DSwiftASN1_DIR=" + os.path.join(args.build_dirs["swift-asn1"], "cmake/modules"), + "-DSwiftCertificates_DIR=" + os.path.join(args.build_dirs["swift-certificates"], "cmake/modules"), + "-DSwiftBuild_DIR=" + os.path.join(args.build_dirs["swift-build"], "cmake/modules"), "-DSWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE=" + args.source_dirs["swift-syntax"], "-DSwiftPMRuntime_MODULE_TRIPLE={}".format(module_triple), ] @@ -770,6 +774,7 @@ def build_swiftpm_with_cmake(args): add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-driver"], "lib")) add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-system"], "lib")) add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-collections"], "lib")) + add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-tools-protocols"], "lib")) add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-asn1"], "lib")) add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-certificates"], "lib")) add_rpath_for_cmake_build(args, os.path.join(args.build_dirs["swift-build"], "lib")) @@ -908,6 +913,7 @@ def get_swiftpm_env_cmd(args): os.path.join(args.build_dirs["swift-driver"], "lib"), os.path.join(args.build_dirs["swift-system"], "lib"), os.path.join(args.build_dirs["swift-collections"], "lib"), + os.path.join(args.build_dirs["swift-tools-protocols"], "lib"), os.path.join(args.build_dirs["swift-asn1"], "lib"), os.path.join(args.build_dirs["swift-certificates"], "lib"), os.path.join(args.build_dirs["swift-build"], "lib"), From 394b430c8f650bafba2c56cca14ce1f4a4ff75b0 Mon Sep 17 00:00:00 2001 From: Robert Connell Date: Tue, 18 Nov 2025 08:44:42 -0500 Subject: [PATCH 6/9] [GH:#9304] Explicit source file declaration in Target's sources causes a performance degradation in TargetSourcesBuilder (#9385) Avoid expensive string array operations when performing target source evaluation. Local timings for target source evaluation of protoc before and after: **Before:** 'swift-protobuf': TargetSourcesBuilder.run() for target 'protoc' took 11.544s **After:** 'swift-protobuf': TargetSourcesBuilder.run() for target 'protoc' took 0.190s CPU cycles for full build of swift-protobuf: **Before:** 33.43 G **After:** 5.72 G Motivation: Fixes: #9304 --- .../PackageLoading/TargetSourcesBuilder.swift | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/Sources/PackageLoading/TargetSourcesBuilder.swift b/Sources/PackageLoading/TargetSourcesBuilder.swift index e218bf3f227..87f235ed3a0 100644 --- a/Sources/PackageLoading/TargetSourcesBuilder.swift +++ b/Sources/PackageLoading/TargetSourcesBuilder.swift @@ -12,6 +12,7 @@ import Basics import Foundation +import OrderedCollections import PackageModel import TSCBasic @@ -33,7 +34,7 @@ public struct TargetSourcesBuilder { public let targetPath: Basics.AbsolutePath /// The list of declared sources in the package manifest. - public let declaredSources: [Basics.AbsolutePath]? + public let declaredSources: OrderedCollections.OrderedSet? /// The list of declared resources in the package manifest. public let declaredResources: [(path: Basics.AbsolutePath, rule: TargetDescription.Resource.Rule)] @@ -89,23 +90,28 @@ public struct TargetSourcesBuilder { ) self.fileSystem = fileSystem - self.observabilityScope = observabilityScope.makeChildScope(description: "TargetSourcesBuilder") { + let childObservabilityScope = observabilityScope.makeChildScope(description: "TargetSourcesBuilder") { var metadata = ObservabilityMetadata.packageMetadata(identity: packageIdentity, kind: packageKind) metadata.moduleName = target.name return metadata } + self.observabilityScope = childObservabilityScope - let declaredSources = target.sources?.compactMap { try? AbsolutePath(validating: $0, relativeTo: path) } - if let declaredSources { - // Diagnose duplicate entries. - let duplicates = declaredSources.spm_findDuplicateElements() - if !duplicates.isEmpty { - for duplicate in duplicates { - self.observabilityScope.emit(warning: "found duplicate sources declaration in the package manifest: \(duplicate.map{ $0.pathString }[0])") + var declaredSources: OrderedCollections.OrderedSet? = nil + + if let targetSources = target.sources { + for targetSource in targetSources { + if let targetSourcePath = try? AbsolutePath(validating: targetSource, relativeTo: path) { + declaredSources = declaredSources ?? OrderedCollections.OrderedSet() + if declaredSources?.updateOrAppend(targetSourcePath) != nil { + childObservabilityScope.emit(warning: "found duplicate sources declaration in the package manifest: \(targetSourcePath.pathString)") + + } } } } - self.declaredSources = declaredSources?.spm_uniqueElements() + + self.declaredSources = declaredSources self.declaredResources = (try? target.resources.map { (path: try AbsolutePath(validating: $0.path, relativeTo: path), rule: $0.rule) @@ -237,7 +243,7 @@ public struct TargetSourcesBuilder { toolsVersion: ToolsVersion, rules: [FileRuleDescription], declaredResources: [(path: Basics.AbsolutePath, rule: TargetDescription.Resource.Rule)], - declaredSources: [Basics.AbsolutePath]?, + declaredSources: OrderedCollections.OrderedSet?, matchingResourceRuleHandler: (Basics.AbsolutePath) -> () = { _ in }, observabilityScope: ObservabilityScope ) -> FileRuleDescription.Rule { @@ -257,11 +263,10 @@ public struct TargetSourcesBuilder { // Match any sources explicitly declared in the manifest file. if let declaredSources { - for sourcePath in declaredSources { - if path.isDescendantOfOrEqual(to: sourcePath) { - if matchedRule != .none { - observabilityScope.emit(error: "duplicate rule found for file at '\(path)'") - } + if isDescendantOfOrEqualToAny(path, declaredSources) { + if matchedRule != .none { + observabilityScope.emit(error: "duplicate rule found for file at '\(path)'") + } // Check for header files as they're allowed to be mixed with sources. if let ext = path.extension, @@ -276,10 +281,8 @@ public struct TargetSourcesBuilder { // The source file might have been declared twice so // exit on first match. // FIXME: We should emitting warnings for duplicate// declarations. - break } } - } // We haven't found a rule using that's explicitly declared in the manifest // so try doing an automatic match. @@ -302,6 +305,23 @@ public struct TargetSourcesBuilder { return matchedRule } + + private static func isDescendantOfOrEqualToAny(_ path: Basics.AbsolutePath, _ ancestorPaths: OrderedCollections.OrderedSet) -> Bool { + var currentPath = path + while true { + if ancestorPaths.contains(currentPath) { + return true + } + + let parentPath = currentPath.parentDirectory + if parentPath == currentPath { + break + } + currentPath = parentPath + } + + return false + } /// Returns the `Resource` file associated with a file and a particular rule, if there is one. private static func resource(for path: Basics.AbsolutePath, with rule: FileRuleDescription.Rule, defaultLocalization: String?, targetName: String, targetPath: Basics.AbsolutePath, observabilityScope: ObservabilityScope) -> Resource? { From 4f5a63478596ef668dd903ebb3333a760ba6d63a Mon Sep 17 00:00:00 2001 From: Dave Inglis Date: Tue, 18 Nov 2025 09:38:15 -0500 Subject: [PATCH 7/9] Mark purgeCacheWithoutPackage withKnowIssue for AL2 (#9386) - this test seems to cause a crash in libcrypto rdar://134238535 --- Tests/CommandsTests/PackageCommandTests.swift | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 317a570b41d..c0b9481f621 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -3069,22 +3069,28 @@ struct PackageCommandTests { func purgeCacheWithoutPackage( data: BuildData, ) async throws { - // Create a temporary directory without Package.swift - try await fixture(name: "Miscellaneous") { fixturePath in - let tempDir = fixturePath.appending("empty-dir-for-purge-test") - try localFileSystem.createDirectory(tempDir, recursive: true) - - // Use a unique temporary cache directory to avoid conflicts with parallel tests - try await withTemporaryDirectory(removeTreeOnDeinit: true) { cacheDir in - let result = try await executeSwiftPackage( - tempDir, - configuration: data.config, - extraArgs: ["purge-cache", "--cache-path", cacheDir.pathString], - buildSystem: data.buildSystem - ) + try await withKnownIssue( + isIntermittent: ProcessInfo.isHostAmazonLinux2() //rdar://134238535 + ) { + // Create a temporary directory without Package.swift + try await fixture(name: "Miscellaneous") { fixturePath in + let tempDir = fixturePath.appending("empty-dir-for-purge-test") + try localFileSystem.createDirectory(tempDir, recursive: true) + + // Use a unique temporary cache directory to avoid conflicts with parallel tests + try await withTemporaryDirectory(removeTreeOnDeinit: true) { cacheDir in + let result = try await executeSwiftPackage( + tempDir, + configuration: data.config, + extraArgs: ["purge-cache", "--cache-path", cacheDir.pathString], + buildSystem: data.buildSystem + ) - #expect(!result.stderr.contains("Could not find Package.swift")) + #expect(!result.stderr.contains("Could not find Package.swift")) + } } + } when: { + ProcessInfo.isHostAmazonLinux2() } } From ae9ba6d6cf807e9e495d909088339f8a050f2168 Mon Sep 17 00:00:00 2001 From: Paul LeMarquand Date: Tue, 18 Nov 2025 15:46:47 -0500 Subject: [PATCH 8/9] Fix setting SPECIALIZATION_SDK_OPTIONS, .ARCHS (#9379) The code to build up the SPECIALIZATION_SDK_OPTIONS list was appending to the existing list, but the list is not guarenteed to be initialized. If it isn't initialized, the append never happens and the setting is dropped. --- .../Package.swift | 23 ++++++++++++++++ .../Sources/Executable/main.swift | 1 + .../PackageWithSDKSpecialization.swift | 3 +++ .../SwiftBuildSupport/PackagePIFBuilder.swift | 4 +-- .../PIFBuilderTests.swift | 26 +++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 Fixtures/PIFBuilder/PackageWithSDKSpecialization/Package.swift create mode 100644 Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/Executable/main.swift create mode 100644 Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/PackageWithSDKSpecialization/PackageWithSDKSpecialization.swift diff --git a/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Package.swift b/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Package.swift new file mode 100644 index 00000000000..7388c628606 --- /dev/null +++ b/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Package.swift @@ -0,0 +1,23 @@ +// swift-tools-version: 6.2 + +import PackageDescription + +let package = Package( + name: "PackageWithSDKSpecialization", + platforms: [ .macOS("10.15.foo") ], + products: [ + .library( + name: "PackageWithSDKSpecialization", + targets: ["PackageWithSDKSpecialization"]), + ], + targets: [ + .target( + name: "PackageWithSDKSpecialization", + dependencies: [] + ), + .target( + name: "Executable", + dependencies: ["PackageWithSDKSpecialization"] + ), + ] +) diff --git a/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/Executable/main.swift b/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/Executable/main.swift new file mode 100644 index 00000000000..f7cf60e14f9 --- /dev/null +++ b/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/Executable/main.swift @@ -0,0 +1 @@ +print("Hello, world!") diff --git a/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/PackageWithSDKSpecialization/PackageWithSDKSpecialization.swift b/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/PackageWithSDKSpecialization/PackageWithSDKSpecialization.swift new file mode 100644 index 00000000000..13454213039 --- /dev/null +++ b/Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/PackageWithSDKSpecialization/PackageWithSDKSpecialization.swift @@ -0,0 +1,3 @@ +struct PackageWithSDKSpecialization { + var text = "Hello, World!" +} diff --git a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift index 75e813edf31..53c7a428be8 100644 --- a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift @@ -581,7 +581,7 @@ public final class PackagePIFBuilder { log(.warning, "Ignoring options '\(platformOptions.joined(separator: " "))' specified for unknown platform \(platform.name)") continue } - settings[.SPECIALIZATION_SDK_OPTIONS, pifPlatform]?.append(contentsOf: platformOptions) + settings[.SPECIALIZATION_SDK_OPTIONS, pifPlatform] = (settings[.SPECIALIZATION_SDK_OPTIONS, pifPlatform] ?? []) + platformOptions } let deviceFamilyIDs: Set = self.delegate.deviceFamilyIDs() @@ -607,7 +607,7 @@ public final class PackagePIFBuilder { } catch { preconditionFailure("Unhandled arm64e platform: \(error)") } - settings[.ARCHS, pifPlatform]?.append(contentsOf: ["arm64e"]) + settings[.ARCHS, pifPlatform] = (settings[.ARCHS, pifPlatform] ?? []) + ["arm64e"] } } diff --git a/Tests/SwiftBuildSupportTests/PIFBuilderTests.swift b/Tests/SwiftBuildSupportTests/PIFBuilderTests.swift index 4404468b460..80f00260ee5 100644 --- a/Tests/SwiftBuildSupportTests/PIFBuilderTests.swift +++ b/Tests/SwiftBuildSupportTests/PIFBuilderTests.swift @@ -118,6 +118,19 @@ extension SwiftBuildSupport.PIF.Project { throw StringError("Multiple targets named \(name) in PIF project") } } + + fileprivate func buildConfig(named name: String) throws -> SwiftBuild.ProjectModel.BuildConfig { + let matchingConfigs = underlying.buildConfigs.filter { + $0.name == name + } + if matchingConfigs.isEmpty { + throw StringError("No config named \(name) in PIF project") + } else if matchingConfigs.count > 1 { + throw StringError("Multiple configs named \(name) in PIF project") + } else { + return matchingConfigs[0] + } + } } extension SwiftBuild.ProjectModel.BaseTarget { @@ -177,6 +190,19 @@ struct PIFBuilderTests { } } + @Test func packageWithInternal() async throws { + try await withGeneratedPIF(fromFixture: "PIFBuilder/PackageWithSDKSpecialization") { pif, observabilitySystem in + let errors = observabilitySystem.diagnostics.filter { $0.severity == .error } + #expect(errors.isEmpty, "Expected no errors during PIF generation, but got: \(errors)") + + let releaseConfig = try pif.workspace + .project(named: "PackageWithSDKSpecialization") + .buildConfig(named: "Release") + + #expect(releaseConfig.settings[.SPECIALIZATION_SDK_OPTIONS, .macOS] == ["foo"]) + } + } + @Test func pluginWithBinaryTargetDependency() async throws { try await withGeneratedPIF(fromFixture: "Miscellaneous/Plugins/BinaryTargetExePlugin") { pif, observabilitySystem in // Verify that PIF generation succeeds for a package with a plugin that depends on a binary target From 84b3e6e7db884f5e2e5a6b23d2b032a4f4e7c8de Mon Sep 17 00:00:00 2001 From: Mishal Shah Date: Wed, 19 Nov 2025 07:05:30 -0800 Subject: [PATCH 9/9] [CI] Add support for GitHub Actions (#9391) Known issues: * https://github.com/swiftlang/swift-package-manager/issues/9393 * We are only building, and not running testing due to timeout. * Testing for Swift SDK for Android and static sdk are currently disabled. --- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 94 ++++++++++--------- .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 70 +++++++------- .github/scripts/prebuild.ps1 | 40 ++++++++ .github/scripts/prebuild.sh | 85 +++++++++++++++++ .github/workflows/automerge.yml | 23 +++++ .github/workflows/pull_request.yml | 40 ++++++++ .license_header_template | 11 +++ .licenseignore | 10 ++ .../PackageRegistry/registry.openapi.yaml | 18 ++-- Sources/Basics/Concurrency/AsyncProcess.swift | 8 +- .../PackageRegistryCommand+Auth.swift | 2 + .../Plugins/DefaultPluginScriptRunner.swift | 30 +++--- .../BuildPrebuilts.swift | 4 +- Utilities/Docker/docker-compose.yaml | 2 +- 14 files changed, 332 insertions(+), 105 deletions(-) create mode 100644 .github/scripts/prebuild.ps1 create mode 100755 .github/scripts/prebuild.sh create mode 100644 .github/workflows/automerge.yml create mode 100644 .github/workflows/pull_request.yml create mode 100644 .license_header_template create mode 100644 .licenseignore diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index ac3bd5b4867..43f67913d73 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -2,46 +2,54 @@ name: Bug Report description: Something isn't working as expected labels: [bug] body: -- type: checkboxes - id: cat-preferences - attributes: - label: "Is it reproducible with SwiftPM command-line tools: `swift build`, `swift test`, `swift package` etc?" - description: "Issues related to closed-source software are not tracked by this repository and will be closed. For Xcode and `xcodebuild`, please file a feedback at https://feedbackassistant.apple.com instead." - options: - - label: Confirmed reproduction steps with SwiftPM CLI. The description text _must_ include reproduction steps with either of command-line SwiftPM commands, `swift build`, `swift test`, `swift package` etc. - required: true -- type: textarea - attributes: - label: Description - validations: - required: true -- type: textarea - attributes: - label: Expected behavior - description: What you expected to happen. - validations: - required: false -- type: textarea - attributes: - label: Actual behavior - description: What actually happened. - validations: - required: false -- type: textarea - attributes: - label: Steps to reproduce - placeholder: | - 1. ... - 2. ... - validations: - required: false -- type: input - attributes: - label: Swift Package Manager version/commit hash - validations: - required: false -- type: textarea - attributes: - label: Swift & OS version (output of `swift --version ; uname -a`) - validations: - required: false + - type: checkboxes + id: cat-preferences + attributes: + label: >- + Is it reproducible with SwiftPM command-line tools: `swift build`, + `swift test`, `swift package` etc? + description: >- + Issues related to closed-source software are not tracked by this + repository and will be closed. For Xcode and `xcodebuild`, please + file a feedback at https://feedbackassistant.apple.com instead." + options: + - label: >- + Confirmed reproduction steps with SwiftPM CLI. The description + text _must_ include reproduction steps with either of command-line + SwiftPM commands, `swift build`, `swift test`, `swift package` etc. + required: true + - type: textarea + attributes: + label: Description + validations: + required: true + - type: textarea + attributes: + label: Expected behavior + description: What you expected to happen. + validations: + required: false + - type: textarea + attributes: + label: Actual behavior + description: What actually happened. + validations: + required: false + - type: textarea + attributes: + label: Steps to reproduce + placeholder: | + 1. ... + 2. ... + validations: + required: false + - type: input + attributes: + label: Swift Package Manager version/commit hash + validations: + required: false + - type: textarea + attributes: + label: Swift & OS version (output of `swift --version ; uname -a`) + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index 7c2149d3d0a..054a093da11 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -2,38 +2,38 @@ name: Feature Request description: A suggestion for a new feature labels: [enhancement] body: -- type: textarea - attributes: - label: Description - validations: - required: true -- type: textarea - attributes: - label: Expected behavior - description: What you expected to happen. - validations: - required: false -- type: textarea - attributes: - label: Actual behavior - description: What actually happened. - validations: - required: false -- type: textarea - attributes: - label: Steps to reproduce - placeholder: | - 1. ... - 2. ... - validations: - required: false -- type: input - attributes: - label: Swift Package Manager version/commit hash - validations: - required: false -- type: textarea - attributes: - label: Swift & OS version (output of `swift --version && uname -a`) - validations: - required: false + - type: textarea + attributes: + label: Description + validations: + required: true + - type: textarea + attributes: + label: Expected behavior + description: What you expected to happen. + validations: + required: false + - type: textarea + attributes: + label: Actual behavior + description: What actually happened. + validations: + required: false + - type: textarea + attributes: + label: Steps to reproduce + placeholder: | + 1. ... + 2. ... + validations: + required: false + - type: input + attributes: + label: Swift Package Manager version/commit hash + validations: + required: false + - type: textarea + attributes: + label: Swift & OS version (output of `swift --version && uname -a`) + validations: + required: false diff --git a/.github/scripts/prebuild.ps1 b/.github/scripts/prebuild.ps1 new file mode 100644 index 00000000000..1e40dfa412c --- /dev/null +++ b/.github/scripts/prebuild.ps1 @@ -0,0 +1,40 @@ +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) 2025 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 +## +##===----------------------------------------------------------------------===## + +param ( + [switch]$SkipAndroid, + [switch]$InstallCMake +) + +# winget isn't easily made available in containers, so use chocolatey +Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + +if ($InstallCMake) { + choco install -y cmake --installargs 'ADD_CMAKE_TO_PATH=System' --apply-install-arguments-to-dependencies + choco install -y ninja + + Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 + refreshenv + + # Let swiftc find the path to link.exe in the CMake smoke test + $env:Path += ";$(Split-Path -Path "$(& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" "-latest" -products Microsoft.VisualStudio.Product.BuildTools -find VC\Tools\MSVC\*\bin\HostX64\x64\link.exe)" -Parent)" +} + +if (-not $SkipAndroid) { + choco install -y android-ndk + + Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 + refreshenv + + # Work around a bug in the package causing the env var to be set incorrectly + $env:ANDROID_NDK_ROOT = $env:ANDROID_NDK_ROOT.replace('-windows.zip','') +} diff --git a/.github/scripts/prebuild.sh b/.github/scripts/prebuild.sh new file mode 100755 index 00000000000..1cd6d3cd298 --- /dev/null +++ b/.github/scripts/prebuild.sh @@ -0,0 +1,85 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) 2025 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 +## +##===----------------------------------------------------------------------===## + +set -e + +if [[ $(uname) == Darwin ]] ; then + if [[ "$INSTALL_CMAKE" == "1" ]] ; then + mkdir -p "$RUNNER_TOOL_CACHE" + if ! command -v cmake >/dev/null 2>&1 ; then + curl -fsSLO https://github.com/Kitware/CMake/releases/download/v4.1.2/cmake-4.1.2-macos-universal.tar.gz + echo '3be85f5b999e327b1ac7d804cbc9acd767059e9f603c42ec2765f6ab68fbd367 cmake-4.1.2-macos-universal.tar.gz' > cmake-4.1.2-macos-universal.tar.gz.sha256 + sha256sum -c cmake-4.1.2-macos-universal.tar.gz.sha256 + tar -xf cmake-4.1.2-macos-universal.tar.gz + ln -s "$PWD/cmake-4.1.2-macos-universal/CMake.app/Contents/bin/cmake" "$RUNNER_TOOL_CACHE/cmake" + fi + if ! command -v ninja >/dev/null 2>&1 ; then + curl -fsSLO https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-mac.zip + echo 'da7797794153629aca5570ef7c813342d0be214ba84632af886856e8f0063dd9 ninja-mac.zip' > ninja-mac.zip.sha256 + sha256sum -c ninja-mac.zip.sha256 + unzip ninja-mac.zip + rm -f ninja-mac.zip + mv ninja "$RUNNER_TOOL_CACHE/ninja" + fi + fi +elif command -v apt-get >/dev/null 2>&1 ; then # bookworm, noble, jammy + export DEBIAN_FRONTEND=noninteractive + + apt-get update -y + + # Build dependencies + apt-get install -y libsqlite3-dev libncurses-dev + + # Debug symbols + apt-get install -y libc6-dbg + + if [[ "$INSTALL_CMAKE" == "1" ]] ; then + apt-get install -y cmake ninja-build + fi + + # Android NDK + dpkg_architecture="$(dpkg --print-architecture)" + if [[ "$SKIP_ANDROID" != "1" ]] && [[ "$dpkg_architecture" == amd64 ]] ; then + eval "$(cat /etc/os-release)" + case "$VERSION_CODENAME" in + bookworm|jammy) + : # Not available + ;; + noble) + apt-get install -y google-android-ndk-r26c-installer + ;; + *) + echo "Unable to fetch Android NDK for unknown Linux distribution: $VERSION_CODENAME" >&2 + exit 1 + esac + else + echo "Skipping Android NDK installation on $dpkg_architecture" >&2 + fi +elif command -v dnf >/dev/null 2>&1 ; then # rhel-ubi9 + dnf update -y + + # Build dependencies + dnf install -y sqlite-devel ncurses-devel + + # Debug symbols + dnf debuginfo-install -y glibc +elif command -v yum >/dev/null 2>&1 ; then # amazonlinux2 + yum update -y + + # Build dependencies + yum install -y sqlite-devel ncurses-devel + + # Debug symbols + yum install -y yum-utils + debuginfo-install -y glibc +fi diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 00000000000..e773ad737f2 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,23 @@ +name: Create PR to merge main into release branch +# In the first period after branching the release branch, +# we typically want to include many changes from `main` in the release branch. +# This workflow automatically creates a PR to merge the main into the release branch. +# Later in the release cycle we should stop this practice to avoid landing risky changes by disabling this workflow. +# To do so, disable the workflow as described in https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow +permissions: + contents: read +on: + schedule: + - cron: '0 9 * * MON' + workflow_dispatch: +jobs: + create_merge_pr: + name: Create PR to merge main into release branch + uses: swiftlang/github-workflows/.github/workflows/create_automerge_pr.yml@main + with: + head_branch: main + base_branch: release/6.3 + permissions: + contents: write + pull-requests: write + if: (github.event_name == 'schedule' && github.repository == 'swiftlang/swift-package-manager') || (github.event_name != 'schedule') # Ensure that we don't run this on a schedule in a fork diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 00000000000..881f66b67b5 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,40 @@ +name: Pull request + +permissions: + contents: read + +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tests: + name: Test + uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main + with: + linux_os_versions: '["amazonlinux2", "bookworm", "noble", "jammy", "rhel-ubi9"]' + linux_swift_versions: '["nightly-main"]' + linux_pre_build_command: ./.github/scripts/prebuild.sh + linux_build_command: 'swift build' + windows_swift_versions: '["nightly-main"]' + windows_pre_build_command: 'Invoke-Program .\.github\scripts\prebuild.ps1' + windows_build_command: 'Invoke-Program swift build' + enable_ios_checks: true + enable_macos_checks: true + macos_exclude_xcode_versions: "[{\"xcode_version\": \"16.3\"}, {\"xcode_version\": \"16.4\"}]" + macos_build_command: 'swift build' + + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + license_header_check_project_name: "Swift" + license_header_check_enabled: false + unacceptable_language_check_enabled: false + api_breakage_check_enabled: false + format_check_enabled: false + shell_check_enabled: false diff --git a/.license_header_template b/.license_header_template new file mode 100644 index 00000000000..52d6f2786e2 --- /dev/null +++ b/.license_header_template @@ -0,0 +1,11 @@ +@@===----------------------------------------------------------------------===@@ +@@ +@@ This source file is part of the Swift open source project +@@ +@@ Copyright (c) YEARS 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 +@@ +@@===----------------------------------------------------------------------===@@ diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 00000000000..e7babf0caf4 --- /dev/null +++ b/.licenseignore @@ -0,0 +1,10 @@ +**/*.mlmodel +**/*.pbxproj +**/*.png +**/*.xcworkspacedata +**/Package.swift +.dir-locals.el +.editorconfig +.swift-version +CODEOWNERS +Package.swift diff --git a/Documentation/PackageRegistry/registry.openapi.yaml b/Documentation/PackageRegistry/registry.openapi.yaml index 99f9b5ddb16..1ae22231c75 100644 --- a/Documentation/PackageRegistry/registry.openapi.yaml +++ b/Documentation/PackageRegistry/registry.openapi.yaml @@ -225,12 +225,12 @@ paths: schema: type: string description: |- - One value for each version-specific package manifest file in the release's source archive, + One value for each version-specific package manifest file in the release's source archive, whose filename matches the following regular expression pattern: `\APackage@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift\z` - Each link value should have the alternate relation type, a filename attribute set to the version-specific package manifest filename - (for example, Package@swift-4.swift), and a swift-tools-version attribute set to the Swift tools version specified by the package + Each link value should have the alternate relation type, a filename attribute set to the version-specific package manifest filename + (for example, Package@swift-4.swift), and a swift-tools-version attribute set to the Swift tools version specified by the package manifest file (for example, 4.0 for a manifest beginning with the comment // swift-tools-version:4.0). content: text/x-swift: @@ -277,8 +277,8 @@ paths: type: string example: 'sha-256=oqxUzyX7wa0AKPA/CqS5aDO4O7BaFOUQiSuyfepNyBI=' Content-Disposition: - description: |- - A header set to attachment with a filename parameter equal to the name of the package followed by a hyphen (-), + description: |- + A header set to attachment with a filename parameter equal to the name of the package followed by a hyphen (-), the version number, and file extension (for example, "LinkedList-1.1.1.zip") schema: type: string @@ -455,7 +455,7 @@ components: PackageLinks: schema: type: string - description: |- + description: |- A set of related links. An example: @@ -583,13 +583,13 @@ components: format: uri description: |- A URI reference that identifies the problem type. - This specification encourages that, when dereferenced, + This specification encourages that, when dereferenced, it provides human-readable documentation for the problem type. example: 'https://example.com/problem/invalid-request-parameters' title: type: string description: |- - A short, human-readable summary of the problem type. + A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. example: 'Invalid request parameters' @@ -682,7 +682,7 @@ components: type: string format: date-time description: |- - The ISO 8601-formatted datetime string of when the package release was published, as recorded by the registry. + The ISO 8601-formatted datetime string of when the package release was published, as recorded by the registry. See related `originalPublicationTime` in metadata. required: - id diff --git a/Sources/Basics/Concurrency/AsyncProcess.swift b/Sources/Basics/Concurrency/AsyncProcess.swift index 86222f8fa67..17149e833bc 100644 --- a/Sources/Basics/Concurrency/AsyncProcess.swift +++ b/Sources/Basics/Concurrency/AsyncProcess.swift @@ -567,7 +567,9 @@ package final class AsyncProcess { return stdinPipe.fileHandleForWriting #elseif(!canImport(Darwin) || os(macOS)) // Initialize the spawn attributes. - #if canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD) + #if os(Android) + var attributes: posix_spawnattr_t! = nil + #elseif canImport(Darwin) || os(OpenBSD) || os(FreeBSD) var attributes: posix_spawnattr_t? = nil #else var attributes = posix_spawnattr_t() @@ -612,7 +614,9 @@ package final class AsyncProcess { posix_spawnattr_setflags(&attributes, Int16(flags)) // Setup the file actions. - #if canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD) + #if os(Android) + var fileActions: posix_spawn_file_actions_t! = nil + #elseif canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD) var fileActions: posix_spawn_file_actions_t? = nil #else var fileActions = posix_spawn_file_actions_t() diff --git a/Sources/PackageRegistryCommand/PackageRegistryCommand+Auth.swift b/Sources/PackageRegistryCommand/PackageRegistryCommand+Auth.swift index a7a5cb35521..2c01cf1413d 100644 --- a/Sources/PackageRegistryCommand/PackageRegistryCommand+Auth.swift +++ b/Sources/PackageRegistryCommand/PackageRegistryCommand+Auth.swift @@ -82,6 +82,8 @@ private func readpassword(_ prompt: String) throws -> String { return String(cString: passwordPtr) } + #elseif canImport(Android) + throw StringError("unable to read input - not implemented on this platform") #else // GNU C implementation of getpass has no limit on the password length // (https://man7.org/linux/man-pages/man3/getpass.3.html) diff --git a/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift b/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift index c1f487c7bba..a5b450a6f5a 100644 --- a/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift +++ b/Sources/SPMBuildCore/Plugins/DefaultPluginScriptRunner.swift @@ -23,6 +23,10 @@ import class Basics.AsyncProcess import struct TSCUtility.SerializedDiagnostics +#if os(Android) +import Android +#endif + /// A plugin script runner that compiles the plugin source files as an executable binary for the host platform, and invokes it as a subprocess. public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { private let fileSystem: FileSystem @@ -51,7 +55,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { self.cancellator = Cancellator(observabilityScope: .none) self.verboseOutput = verboseOutput } - + /// Starts evaluating a plugin by compiling it and running it as a subprocess. The name is used as the basename for the executable and auxiliary files. The tools version controls the availability of APIs in PackagePlugin, and should be set to the tools version of the package that defines the plugin (not the package containing the target to which it is being applied). This function returns immediately and then repeated calls the output handler on the given callback queue as plain-text output is received from the plugin, and then eventually calls the completion handler on the given callback queue once the plugin is done. public func runPluginScript( sourceFiles: [Basics.AbsolutePath], @@ -109,7 +113,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { public var hostTriple: Triple { return self.toolchain.targetTriple } - + /// Starts compiling a plugin script asynchronously and when done, calls the completion handler on the callback queue with the results (including the path of the compiled plugin executable and with any emitted diagnostics, etc). Existing compilation results that are still valid are reused, if possible. This function itself returns immediately after starting the compile. Note that the completion handler only receives a `.failure` result if the compiler couldn't be invoked at all; a non-zero exit code from the compiler still returns `.success` with a full compilation result that notes the error in the diagnostics (in other words, a `.failure` result only means "failure to invoke the compiler"). public func compilePluginScript( sourceFiles: [Basics.AbsolutePath], @@ -136,7 +140,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { // We use the toolchain's Swift compiler for compiling the plugin. var commandLine = [self.toolchain.swiftCompilerPathForManifests.pathString] - + observabilityScope.emit(debug: "Using compiler \(self.toolchain.swiftCompilerPathForManifests.pathString)") // Get access to the path containing the PackagePlugin module and library. @@ -246,7 +250,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { completion(.failure(DefaultPluginScriptRunnerError.compilationPreparationFailed(error: error))) } } - + // Hash the compiler inputs to decide whether we really need to recompile. let compilerInputHash: String? do { @@ -267,7 +271,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { observabilityScope.emit(debug: "Couldn't compute hash of plugin compilation inputs", underlyingError: error) compilerInputHash = .none } - + /// Persisted information about the last time the compiler was invoked. struct PersistedCompilationState: Codable { var commandLine: [String] @@ -279,7 +283,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { case exit(code: Int32) case abnormal(exception: UInt32) case signal(number: Int32) - + init(_ processExitStatus: AsyncProcessResult.ExitStatus) { switch processExitStatus { case .terminated(let code): @@ -294,12 +298,12 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { } } } - + var succeeded: Bool { return result == .exit(code: 0) } } - + // Check if we already have a compiled executable and a persisted state (we only recompile if things have changed). let stateFilePath = self.cacheDir.appending(component: execName + "-state" + ".json") var compilationState: PersistedCompilationState? = .none @@ -310,7 +314,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { path: stateFilePath, fileSystem: fileSystem, as: PersistedCompilationState.self) - + // If it succeeded last time and the compiler inputs are the same, we don't need to recompile. if previousState.succeeded && previousState.inputHash == compilerInputHash { compilationState = previousState @@ -321,7 +325,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { observabilityScope.emit(debug: "Couldn't read previous compilation state", underlyingError: error) } } - + // If we still have a compilation state, it means the executable is still valid and we don't need to do anything. if let compilationState { // Just call the completion handler with the persisted results. @@ -350,7 +354,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { catch { observabilityScope.emit(debug: "Couldn't clean up before invoking compiler", underlyingError: error) } - + // Now invoke the compiler asynchronously. AsyncProcess.popen(arguments: commandLine, environment: environment, queue: callbackQueue) { // We are now on our caller's requested callback queue, so we just call the completion handler directly. @@ -388,7 +392,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { // Tell the delegate that we're done compiling the plugin, passing it the result. delegate.didCompilePlugin(result: result) - + // Also return the result to the caller. return result }) @@ -487,7 +491,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable { process.environment = .init(env) process.currentDirectoryURL = workingDirectory.asURL - + // Set up a pipe for sending structured messages to the plugin on its stdin. let stdinPipe = Pipe() let outputHandle = stdinPipe.fileHandleForWriting diff --git a/Sources/swift-build-prebuilts/BuildPrebuilts.swift b/Sources/swift-build-prebuilts/BuildPrebuilts.swift index 09e46bb518d..88bf4516cd3 100644 --- a/Sources/swift-build-prebuilts/BuildPrebuilts.swift +++ b/Sources/swift-build-prebuilts/BuildPrebuilts.swift @@ -251,7 +251,7 @@ struct BuildPrebuilts: AsyncParsableCommand { guard let swiftVersion = try computeSwiftVersion() else { print("Unable to determine swift compiler version") - _exit(1) + Foundation.exit(1) } let id = "swift-syntax" @@ -296,7 +296,7 @@ struct BuildPrebuilts: AsyncParsableCommand { let manifestURL = URL(string: prebuiltsUrl)?.appending(components: id, version, manifestFile) guard let manifestURL else { print("Invalid URL \(prebuiltsUrl)") - _exit(1) + Foundation.exit(1) } var headers = HTTPClientHeaders() diff --git a/Utilities/Docker/docker-compose.yaml b/Utilities/Docker/docker-compose.yaml index 7a6a42fc539..a0b899d60cc 100644 --- a/Utilities/Docker/docker-compose.yaml +++ b/Utilities/Docker/docker-compose.yaml @@ -27,7 +27,7 @@ services: - ~/.ssh:/root/.ssh - ~/.cache:/root/.cache - ~/.swiftpm/cache:/root/.swiftpm/cache - - ~/.swiftpm/configuration:/root/.swiftpm/config # old location, remove after 5.6 + - ~/.swiftpm/configuration:/root/.swiftpm/config # old location, remove after 5.6 - ~/.swiftpm/configuration:/root/.swiftpm/configuration - ~/.swiftpm/security:/root/.swiftpm/security # swift-package-manager code