From 8855839f6660055381529cfd855ed8dabeb786ca Mon Sep 17 00:00:00 2001 From: danielhanchen Date: Fri, 7 Aug 2026 10:19:38 +0000 Subject: [PATCH] Prototype: pin the CPU legs' glibc floor with a container, not the runner Untested against a real runner. Prototype for review, not to merge. ubuntu-22.04 and ubuntu-22.04-arm retire 2027-04-17. Today those labels are what holds the bundles at glibc 2.35 / GLIBCXX <= 3.4.30 so they load on Ubuntu 22.04 and Debian 12, so the labels cannot simply be swapped: a 24.04 build needs GLIBC_2.38. Moving the userspace into a container decouples the floor from the runner image. The build then keeps 2.35 on a 24.04 host, and the same shape survives the 24.04 retirement after it. The CPU legs are the prototype because they are the only Linux build legs with no vendor SDK to install, and because they take their source from download-artifact rather than checkout, so the container needs no git. Adjustments the bare image forces: no privilege prefix, since the container is root and ships none; and ca-certificates, wget, gnupg and lsb-release, which the host image has and ubuntu:22.04 does not, all of which llvm.sh needs on arm64. Also adds the assertion the runner label was silently standing in for. Nothing ever checked the produced floor, so nothing would have caught the label drifting. objdump now reports the highest GLIBC_x.y across bin/ and fails the job above 2.35, which makes the container's effect checkable rather than assumed. Not converted: CUDA, ROCm and Vulkan. Each installs a vendor toolkit whose behaviour inside a container needs its own test, and the arm64 CUDA leg is already on ubuntu-24.04-arm at glibc 2.39, so its floor is a separate question. --- .github/workflows/unsloth-prebuilt-cpu.yml | 43 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/.github/workflows/unsloth-prebuilt-cpu.yml b/.github/workflows/unsloth-prebuilt-cpu.yml index 9824eed008f6..5df760989566 100644 --- a/.github/workflows/unsloth-prebuilt-cpu.yml +++ b/.github/workflows/unsloth-prebuilt-cpu.yml @@ -48,12 +48,13 @@ jobs: build-linux: name: linux/${{ matrix.arch }} runs-on: ${{ matrix.runner }} + container: ${{ matrix.container }} strategy: fail-fast: false matrix: include: - - { arch: x64, runner: ubuntu-22.04 } - - { arch: arm64, runner: ubuntu-22.04-arm } + - { arch: x64, runner: ubuntu-24.04, container: 'ubuntu:22.04' } + - { arch: arm64, runner: ubuntu-24.04-arm, container: 'ubuntu:22.04' } steps: # The parent's resolve job built the source tree (upstream base + any mix # PRs, with the build number/commit and Unsloth fingerprint baked @@ -71,11 +72,17 @@ jobs: mkdir -p src tar -xzf "srcpkg/llama.cpp-source-${{ inputs.tag }}.tar.gz" -C src --strip-components=1 + # The container runs as root and the base image ships no sudo, so the + # privilege prefix is dropped. ca-certificates, wget, gnupg and lsb-release + # are present on the host runner image but not in ubuntu:22.04, and + # llvm.sh below needs all four. - name: Install build dependencies run: | set -eux - sudo apt-get update - sudo apt-get install -y build-essential libssl-dev ninja-build + apt-get update + apt-get install -y --no-install-recommends \ + build-essential libssl-dev ninja-build cmake \ + ca-certificates wget gnupg lsb-release xz-utils # arm64 builds on ubuntu-22.04-arm so the bundle keeps the x64 leg's # loader floor (a 24.04 build needs GLIBC_2.38 and fails to load on @@ -88,7 +95,7 @@ jobs: set -eux wget -q https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 19 + ./llvm.sh 19 { echo "CC=clang-19" echo "CXX=clang++-19" @@ -160,6 +167,32 @@ jobs: fi exit 0 + # The whole point of the container is this number, so assert it rather + # than trusting that the image did its job. objdump reports the highest + # GLIBC_x.y any binary asks the loader for; on a 22.04 userspace that is + # 2.35, and a 24.04 build would show 2.38 or higher and fail here. + # + # This is the check the runner label was silently standing in for. It was + # never asserted while the floor came from the runner image, which is why + # nothing would have caught the label drifting. + - name: Assert the glibc floor + run: | + set -euo pipefail + MAX=0.0 + for b in src/build/bin/*; do + [ -f "$b" ] && [ -x "$b" ] || continue + v="$(objdump -T "$b" 2>/dev/null \ + | sed -n 's/.*GLIBC_\([0-9][0-9.]*\).*/\1/p' \ + | sort -V | tail -1)" || true + [ -n "$v" ] || continue + if [ "$(printf '%s\n%s\n' "$MAX" "$v" | sort -V | tail -1)" = "$v" ]; then MAX="$v"; fi + done + echo "highest GLIBC requirement across bin/: ${MAX}" + if [ "$(printf '2.35\n%s\n' "$MAX" | sort -V | tail -1)" != "2.35" ]; then + echo "::error::binaries require GLIBC_${MAX}, above the 2.35 floor: they will not load on Ubuntu 22.04 or Debian 12" + exit 1 + fi + - name: Package bundle (tar.gz) run: | set -eux