diff --git a/.github/scripts/prebuild.sh b/.github/scripts/prebuild.sh index cb77efb6b..a8869f65a 100755 --- a/.github/scripts/prebuild.sh +++ b/.github/scripts/prebuild.sh @@ -72,13 +72,14 @@ elif command -v apt-get >/dev/null 2>&1 ; then # bookworm, noble, jammy else echo "Skipping Android NDK installation on $dpkg_architecture" >&2 fi -elif command -v dnf >/dev/null 2>&1 ; then # rhel-ubi9 +elif command -v dnf >/dev/null 2>&1 ; then # amazonlinux2023, rhel-ubi9 $sudo dnf update -y # Build dependencies $sudo dnf install -y sqlite-devel ncurses-devel python3 # Debug symbols + $sudo dnf install -y 'dnf-command(debuginfo-install)' $sudo dnf debuginfo-install -y glibc elif command -v yum >/dev/null 2>&1 ; then # amazonlinux2 $sudo yum update -y diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index b4d26a6ad..2ff37adf0 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -18,7 +18,7 @@ jobs: needs: [soundness, space-format-check] with: enable_cross_pr_testing: true - linux_os_versions: '["amazonlinux2", "bookworm", "noble", "jammy", "rhel-ubi9"]' + linux_os_versions: '["amazonlinux2", "amazonlinux2023", "bookworm", "noble", "jammy", "rhel-ubi9"]' linux_pre_build_command: ./.github/scripts/prebuild.sh linux_build_command: 'swift test --no-parallel' linux_swift_versions: '["nightly-main", "nightly-6.3"]' diff --git a/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift b/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift index 7865c5291..67cb27a6c 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift @@ -1922,8 +1922,26 @@ public final class LibtoolLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @u public func discoveredLinkerToolsInfo(_ producer: any CommandProducer, _ delegate: any CoreClientTargetDiagnosticProducingDelegate, at toolPath: Path) async -> (any DiscoveredCommandLineToolSpecInfo)? { do { do { + // -version_details is an Apple ld specific option providing parseable output; try that first let commandLine = [toolPath.str, "-version_details"] return try await producer.discoveredCommandLineToolSpecInfo(delegate, nil, commandLine, { executionResult in + struct LDVersionDetails: Decodable { + let version: Version + let architectures: Set + } + + let details: LDVersionDetails + do { + details = try JSONDecoder().decode(LDVersionDetails.self, from: executionResult.stdout) + } catch { + throw CommandLineOutputJSONParsingError(commandLine: commandLine, data: executionResult.stdout, hostOS: producer.hostOperatingSystem) + } + + return DiscoveredLdLinkerToolSpecInfo(linker: .ld64, toolPath: toolPath, toolVersion: details.version, architectures: details.architectures) + }) + } catch let e as CommandLineOutputJSONParsingError { + let vCommandLine = [toolPath.str, "-v"] + return try await producer.discoveredCommandLineToolSpecInfo(delegate, nil, vCommandLine, { executionResult in let gnuLD = [ #/GNU ld version (?[\d.]+)-.*/#, #/GNU ld \(GNU Binutils.*\) (?[\d.]+)/#, @@ -1934,8 +1952,8 @@ public func discoveredLinkerToolsInfo(_ producer: any CommandProducer, _ delegat let goLD = [ #/GNU gold version (?[\d.]+)-.*/#, - #/GNU gold \(GNU Binutils.*\) (?[\d.]+)/#, // Ubuntu "GNU gold (GNU Binutils for Ubuntu 2.38) 1.16", Debian "GNU gold (GNU Binutils for Debian 2.40) 1.16" - #/GNU gold \(version .*\) (?[\d.]+)/#, // Fedora "GNU gold (version 2.40-14.fc39) 1.16", RHEL "GNU gold (version 2.35.2-54.el9) 1.16", Amazon "GNU gold (version 2.29.1-31.amzn2.0.1) 1.14" + #/GNU gold \(GNU Binutils.*\) (?[\d.]+)/#, // Ubuntu "GNU gold (GNU Binutils for Ubuntu 2.38) 1.16", Debian "GNU gold (GNU Binutils for Debian 2.40) 1.16" + #/GNU gold \(version .*\) (?[\d.]+)/#, // Fedora "GNU gold (version 2.40-14.fc39) 1.16", RHEL "GNU gold (version 2.35.2-54.el9) 1.16", Amazon "GNU gold (version 2.29.1-31.amzn2.0.1) 1.14" ] if let match = try goLD.compactMap({ try $0.firstMatch(in: String(decoding: executionResult.stdout, as: UTF8.self)) }).first { @@ -1950,23 +1968,6 @@ public func discoveredLinkerToolsInfo(_ producer: any CommandProducer, _ delegat return DiscoveredLdLinkerToolSpecInfo(linker: .linkExe, toolPath: toolPath, toolVersion: try Version(String(match.output.version)), architectures: Set()) } - struct LDVersionDetails: Decodable { - let version: Version - let architectures: Set - } - - let details: LDVersionDetails - do { - details = try JSONDecoder().decode(LDVersionDetails.self, from: executionResult.stdout) - } catch { - throw CommandLineOutputJSONParsingError(commandLine: commandLine, data: executionResult.stdout, hostOS: producer.hostOperatingSystem) - } - - return DiscoveredLdLinkerToolSpecInfo(linker: .ld64, toolPath: toolPath, toolVersion: details.version, architectures: details.architectures) - }) - } catch let e as CommandLineOutputJSONParsingError { - let vCommandLine = [toolPath.str, "-v"] - return try await producer.discoveredCommandLineToolSpecInfo(delegate, nil, vCommandLine, { executionResult in let lld = [ #/LLD (?[\d.]+).*/#, ] diff --git a/Sources/SWBTestSupport/SkippedTestSupport.swift b/Sources/SWBTestSupport/SkippedTestSupport.swift index 5984e25b6..8bc9342af 100644 --- a/Sources/SWBTestSupport/SkippedTestSupport.swift +++ b/Sources/SWBTestSupport/SkippedTestSupport.swift @@ -233,7 +233,7 @@ extension Trait where Self == Testing.ConditionTrait { } } - package static func requireSystemPackages(apt: String..., yum: String..., freebsd: String..., openbsd: String..., sourceLocation: SourceLocation = #_sourceLocation) -> Self { + package static func requireSystemPackages(apt: String..., dnf: String..., freebsd: String..., openbsd: String..., sourceLocation: SourceLocation = #_sourceLocation) -> Self { enabled("required system packages are not installed") { func installCommand(packageManagerPath: Path, packageNames: String) -> String { switch packageManagerPath.basenameWithoutSuffix { @@ -272,14 +272,19 @@ extension Trait where Self == Testing.ConditionTrait { let apt = try await checkInstalled(hostOS: .linux, packageManagerPath: Path("/usr/bin/apt"), args: ["list", "--installed", "apt"], packages: apt, regex: #/(?.+)\//#) - // spelled `--installed` in newer versions of yum, but Amazon Linux 2 is on older versions - let yum = try await checkInstalled(hostOS: .linux, packageManagerPath: Path("/usr/bin/yum"), args: ["list", "installed", "yum"], packages: yum, regex: #/(?.+)\./#) + let dnf = try await { + guard localFS.exists(Path("/usr/bin/dnf")) else { + // spelled `--installed` in newer versions of yum, but Amazon Linux 2 is on older versions + return try await checkInstalled(hostOS: .linux, packageManagerPath: Path("/usr/bin/yum"), args: ["list", "installed", "yum"], packages: dnf, regex: #/(?.+)\./#) + } + return try await checkInstalled(hostOS: .linux, packageManagerPath: Path("/usr/bin/dnf"), args: ["list", "--installed", "dnf"], packages: dnf, regex: #/(?.+)\./#) + }() let freebsd = try await checkInstalled(hostOS: .freebsd, packageManagerPath: Path("/usr/sbin/pkg"), args: ["info"], packages: freebsd, regex: #/^Name(?:[ ]+): (?.+)$/#) let openbsd = try await checkInstalled(hostOS: .openbsd, packageManagerPath: Path("/usr/sbin/pkg_info"), args: ["-A"], packages: openbsd, regex: #/^(?.+)-.*/#) - return apt && yum && freebsd && openbsd + return apt && dnf && freebsd && openbsd } } diff --git a/Tests/SWBBuildSystemTests/BuildOperationTests.swift b/Tests/SWBBuildSystemTests/BuildOperationTests.swift index 08591cd12..1a5839e92 100644 --- a/Tests/SWBBuildSystemTests/BuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/BuildOperationTests.swift @@ -1002,7 +1002,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests { } /// Check that environment variables are propagated from the user environment correctly. - @Test(.requireSDKs(.host), .skipHostOS(.windows), .requireSystemPackages(apt: "yacc", yum: "byacc")) + @Test(.requireSDKs(.host), .skipHostOS(.windows), .requireSystemPackages(apt: "yacc", dnf: "byacc")) func userEnvironment() async throws { try await withTemporaryDirectory { tmpDirPath async throws -> Void in let testWorkspace = TestWorkspace( @@ -2902,7 +2902,7 @@ That command depends on command in Target 'agg2' (project \'aProject\'): script } /// Check non-UTF8 encoded shell scripts don't cause any unexpected issues. - @Test(.requireSDKs(.host), .skipHostOS(.windows), .requireSystemPackages(apt: "xxd", yum: "vim-common", freebsd: "xxd", openbsd: "vim")) + @Test(.requireSDKs(.host), .skipHostOS(.windows), .requireSystemPackages(apt: "xxd", dnf: "vim-common", freebsd: "xxd", openbsd: "vim")) func nonUTF8ShellScript() async throws { try await withTemporaryDirectory { tmpDir in let testWorkspace = TestWorkspace( diff --git a/Tests/SWBCoreTests/CommandLineToolSpecDiscoveredInfoTests.swift b/Tests/SWBCoreTests/CommandLineToolSpecDiscoveredInfoTests.swift index 781290482..863445535 100644 --- a/Tests/SWBCoreTests/CommandLineToolSpecDiscoveredInfoTests.swift +++ b/Tests/SWBCoreTests/CommandLineToolSpecDiscoveredInfoTests.swift @@ -242,7 +242,7 @@ import SWBMacro } } - @Test(.skipHostOS(.windows), .requireSystemPackages(apt: "libtool", yum: "libtool", freebsd: "libtool", openbsd: "libtool")) + @Test(.skipHostOS(.windows), .requireSystemPackages(apt: "libtool", dnf: "libtool", freebsd: "libtool", openbsd: "libtool")) func discoveredLibtoolSpecInfo() async throws { try await withSpec(LibtoolLinkerSpec.self, .deferred) { (info: DiscoveredLibtoolLinkerToolSpecInfo) in #expect(info.toolPath.basename == "libtool")