diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 2e68a19a8f..dbd34c9380 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -22,6 +22,9 @@ on: type: boolean default: true +env: + LINUX_GLIBC_BASELINE: '2.27' + jobs: preflight: name: Preflight @@ -371,10 +374,14 @@ jobs: name: linux-x64 runtime: linux-x64 publish_profile: linux-x64-NativeAot + cross_image_arch: amd64 + cross_sysroot: /crossrootfs/x64 - os: ubuntu-latest name: linux-arm64 runtime: linux-arm64 publish_profile: linux-arm64-NativeAot + cross_image_arch: arm64 + cross_sysroot: /crossrootfs/arm64 steps: - name: Checkout @@ -393,52 +400,31 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - - name: Install Linux arm64 NativeAOT toolchain - if: matrix.runtime == 'linux-arm64' + - name: Free disk space for cross-build images + if: runner.os == 'Linux' shell: bash run: | - set -euo pipefail - - . /etc/os-release - sudo dpkg --add-architecture arm64 + sudo rm -rf /usr/local/lib/android /opt/ghc || true + df -h / - # Keep the runner's default Ubuntu feeds bound to amd64, then add the - # Ubuntu Ports arm64 feed that provides the target CRT and zlib objects. - if compgen -G "/etc/apt/sources.list.d/*.sources" > /dev/null; then - for source in /etc/apt/sources.list.d/*.sources; do - if ! grep -q '^Architectures:' "$source"; then - sudo sed -i '/^Types: deb$/a Architectures: amd64' "$source" - fi - done - fi + - name: Build Linux cross-compilation image + if: runner.os == 'Linux' + shell: bash + run: | + set -euo pipefail - if [ -f /etc/apt/sources.list ]; then - sudo sed -i -E '/^deb /s/^deb /deb [arch=amd64] /' /etc/apt/sources.list - fi + SDK_TAG="$(jq -er '.sdk.version' global.json)" - sudo tee /etc/apt/sources.list.d/ubuntu-arm64.sources >/dev/null <[A-Za-z_][A-Za-z0-9_]*)@+GLIBC_(?\d+(?:\.\d+)+)')) { + $Version = [version] $Match.Groups['version'].Value + + if ($null -eq $FileHighest -or $Version -gt $FileHighest) { $FileHighest = $Version } + if ($null -eq $HighestVersion -or $Version -gt $HighestVersion) { $HighestVersion = $Version } + + if ($Ceiling -and $Version -gt $Ceiling) { + $Offenders += [pscustomobject]@{ + File = $File.Name + Symbol = $Match.Groups['symbol'].Value + Version = $Version + } + } + } + + $Reported = if ($FileHighest) { "GLIBC_$FileHighest" } else { 'no versioned glibc symbols' } + Write-Host ("{0}: requires {1}" -f $File.Name, $Reported) +} + +if ($null -eq $HighestVersion) { + throw "No versioned glibc symbols were found under '$ResolvedPath'" +} + +Write-Host ("Highest glibc requirement: GLIBC_$HighestVersion") + +if ($Offenders.Count -gt 0) { + Write-Host "References above the GLIBC_$Ceiling baseline:" + $Offenders | + Sort-Object -Property File, Symbol -Unique | + ForEach-Object { Write-Host " $($_.File): $($_.Symbol)@GLIBC_$($_.Version)" } + + throw "Binaries require GLIBC_$HighestVersion but the supported baseline is GLIBC_$Ceiling; they will not start on older distributions." +} + +Write-Output $HighestVersion.ToString() diff --git a/scripts/package-linux.ps1 b/scripts/package-linux.ps1 index 26b3ca09bb..0245d37da8 100644 --- a/scripts/package-linux.ps1 +++ b/scripts/package-linux.ps1 @@ -53,6 +53,10 @@ .PARAMETER IconSourcePath Source path for the installed desktop icon. + +.PARAMETER MinGlibcVersion + Minimum glibc version recorded in the .deb Depends field (e.g. "2.27"). + When omitted, it is detected from the binaries in SourceDir. #> [CmdletBinding()] @@ -81,7 +85,8 @@ param( [string] $Url = 'https://github.com/Devolutions/UniGetUI', [string] $AppExecutableName = 'UniGetUI', [string] $LauncherName = 'unigetui', - [string] $IconSourcePath = (Join-Path $PSScriptRoot '..' 'src' 'SharedAssets' 'Assets' 'Images' 'icon.png') + [string] $IconSourcePath = (Join-Path $PSScriptRoot '..' 'src' 'SharedAssets' 'Assets' 'Images' 'icon.png'), + [string] $MinGlibcVersion = '' ) $ErrorActionPreference = 'Stop' @@ -179,6 +184,13 @@ try { $ControlDir = Join-Path $TmpDir 'control' New-Item -ItemType Directory -Path $ControlDir | Out-Null + $GlibcVersion = $MinGlibcVersion + if (-not $GlibcVersion) { + $GlibcVersion = & (Join-Path $PSScriptRoot 'check-linux-glibc.ps1') -Path $SourceDir | + Select-Object -Last 1 + } + if (-not $GlibcVersion) { throw "Unable to determine the glibc requirement for '$SourceDir'" } + # dpkg requires LF line endings and a trailing newline in control files $ControlLines = @( "Package: $PackageName", @@ -186,6 +198,7 @@ try { "Architecture: $Architecture", "Maintainer: $Maintainer", "Installed-Size: $InstalledSizeKb", + "Depends: libc6 (>= $GlibcVersion)", "Homepage: $Url", "Description: $Description", "Priority: optional",