Build LLVM tools (Linux, per-distro) #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build LLVM tools (Linux, per-distro) | |
| # Builds clang, clang++, clang-format, clang-tidy, lld, llvm-ar, and llvm-nm | |
| # inside RHEL / Rocky UBI containers — one variant per major (8/9/10) — and | |
| # commits the result to the prebuilt/ submodule as 50 MB split parts, matching | |
| # the existing archive format. Each variant is linked against its own glibc | |
| # (8 → 2.28, 9 → 2.34, 10 → 2.39), so setup.sh can pick the closest match. | |
| # | |
| # Two-stage design: | |
| # build (~90 min each, run in parallel) — compiles LLVM per major, uploads | |
| # each archive as a workflow artifact | |
| # commit (~30 sec) — downloads all artifacts, splits, commits, pushes | |
| # | |
| # If only the commit step fails, use "Re-run failed jobs" — it skips the builds. | |
| # | |
| # Run manually once per LLVM version bump whenever VERSION changes in | |
| # tools/toolchains/llvm/setup.sh. | |
| # | |
| # Requirements: | |
| # PREBUILT_TOKEN secret — GitHub PAT (classic) with repo scope on | |
| # airgap-devkit/prebuilt. Settings → Secrets and variables → Actions. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| llvm_version: | |
| description: 'LLVM version — must match VERSION in tools/toolchains/llvm/setup.sh' | |
| required: true | |
| default: '22.1.8' | |
| # ── Job 1: Build (matrix: one variant per RHEL/Rocky major) ─────────────────── | |
| jobs: | |
| build: | |
| name: Build LLVM ${{ inputs.llvm_version }} (UBI ${{ matrix.major }} / glibc ${{ matrix.glibc }}) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { major: "8", glibc: "2.28", image: "registry.access.redhat.com/ubi8/ubi:8.10" } | |
| - { major: "9", glibc: "2.34", image: "registry.access.redhat.com/ubi9/ubi:9.5" } | |
| - { major: "10", glibc: "2.39", image: "registry.access.redhat.com/ubi10/ubi:10.0" } | |
| env: | |
| LLVM_VERSION: ${{ inputs.llvm_version }} | |
| RHEL_TAG: rhel${{ matrix.major }} | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| persist-credentials: false | |
| # Everything below runs inside the matrix UBI container via docker run so | |
| # the resulting binaries are linked against that major's glibc and | |
| # libstdc++, making them compatible with that RHEL/Rocky major and newer. | |
| # | |
| # BUILD_SHARED_LIBS=OFF → each tool is self-contained; no libLLVM.so | |
| # shipped, no RPATH complexity. Runtime deps are the standard system libs | |
| # already present on the target (glibc, libstdc++, zlib). | |
| # | |
| # The UBI default cmake is too old for LLVM 17+; we download a modern | |
| # cmake binary from cmake.org inside the container. | |
| # | |
| # Estimated time: 80-100 minutes on a 2-CPU GitHub Actions runner. | |
| - name: Build LLVM inside UBI ${{ matrix.major }} container | |
| run: | | |
| mkdir -p /tmp/llvm-output | |
| docker run --rm \ | |
| --memory=6g \ | |
| --cpus="$(nproc)" \ | |
| -e LLVM_VERSION \ | |
| -e RHEL_TAG \ | |
| -v /tmp/llvm-output:/output \ | |
| ${{ matrix.image }} \ | |
| bash -euo pipefail -c ' | |
| echo "==> System : $(cat /etc/redhat-release 2>/dev/null || cat /etc/os-release | head -1)" | |
| echo "==> glibc : $(ldd --version | head -1)" | |
| echo "==> Variant: ${RHEL_TAG}" | |
| # ── system packages ──────────────────────────────────────────── | |
| dnf install -y --nodocs \ | |
| gcc gcc-c++ \ | |
| make \ | |
| python3 \ | |
| git \ | |
| xz \ | |
| curl \ | |
| zlib-devel \ | |
| ncurses-devel | |
| echo "==> GCC : $(gcc --version | head -1)" | |
| # Use ninja-build from AppStream if available (faster than make) | |
| dnf install -y ninja-build 2>/dev/null \ | |
| && GENERATOR="Ninja" BUILD_CMD="ninja -j$(nproc)" \ | |
| || { GENERATOR="Unix Makefiles" BUILD_CMD="make -j$(nproc)"; } | |
| echo "==> Build : ${GENERATOR}" | |
| # ── modern cmake ─────────────────────────────────────────────── | |
| CMAKE_VER=3.28.6 | |
| echo "==> Installing cmake ${CMAKE_VER}..." | |
| curl -fsSL \ | |
| "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-linux-x86_64.sh" \ | |
| -o /tmp/cmake.sh | |
| bash /tmp/cmake.sh --skip-license --prefix=/usr/local --exclude-subdir | |
| echo "==> cmake : $(cmake --version | head -1)" | |
| # ── LLVM source ──────────────────────────────────────────────── | |
| echo "==> Downloading llvm-project-${LLVM_VERSION}.src.tar.xz..." | |
| curl -fL --retry 3 \ | |
| "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz" \ | |
| -o /tmp/llvm-src.tar.xz | |
| echo "==> Extracting..." | |
| mkdir -p /tmp/llvm-src | |
| tar -xJf /tmp/llvm-src.tar.xz --strip-components=1 -C /tmp/llvm-src | |
| # ── configure ───────────────────────────────────────────────── | |
| mkdir -p /tmp/llvm-build | |
| cd /tmp/llvm-build | |
| echo "==> Configuring..." | |
| cmake -G "${GENERATOR}" \ | |
| -DCMAKE_BUILD_TYPE=MinSizeRel \ | |
| -DCMAKE_INSTALL_PREFIX=/tmp/llvm-install \ | |
| -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \ | |
| -DLLVM_TARGETS_TO_BUILD="X86" \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DLLVM_INCLUDE_TESTS=OFF \ | |
| -DLLVM_INCLUDE_EXAMPLES=OFF \ | |
| -DLLVM_INCLUDE_BENCHMARKS=OFF \ | |
| -DLLVM_BUILD_DOCS=OFF \ | |
| -DLLVM_ENABLE_DOXYGEN=OFF \ | |
| -DLLVM_ENABLE_SPHINX=OFF \ | |
| -DCLANG_INCLUDE_DOCS=OFF \ | |
| -DCLANG_INCLUDE_TESTS=OFF \ | |
| /tmp/llvm-src/llvm | |
| # ── build ────────────────────────────────────────────────────── | |
| echo "==> Building (80-100 minutes on a 2-CPU runner)..." | |
| ${BUILD_CMD} \ | |
| clang \ | |
| clang-format \ | |
| clang-tidy \ | |
| lld \ | |
| llvm-ar \ | |
| llvm-nm | |
| # ── stage install ───────────────────────────────────────────── | |
| mkdir -p /tmp/llvm-install/bin | |
| for tool in clang clang++ clang-format clang-tidy lld llvm-ar llvm-nm; do | |
| [[ -f "bin/${tool}" ]] && cp "bin/${tool}" /tmp/llvm-install/bin/ | |
| done | |
| [[ ! -f /tmp/llvm-install/bin/clang++ ]] \ | |
| && ln -sf clang /tmp/llvm-install/bin/clang++ | |
| echo "==> Stripping binaries..." | |
| strip /tmp/llvm-install/bin/* 2>/dev/null || true | |
| echo "==> Binary sizes after strip:" | |
| ls -lh /tmp/llvm-install/bin/ | |
| # ── verify ──────────────────────────────────────────────────── | |
| echo "==> Verifying binaries execute on this glibc..." | |
| /tmp/llvm-install/bin/clang-format --version | |
| /tmp/llvm-install/bin/clang --version | |
| # ── package ─────────────────────────────────────────────────── | |
| echo "==> Packaging..." | |
| cd /tmp/llvm-install | |
| tar -cJf "/output/LLVM-${LLVM_VERSION}-Linux-X64-${RHEL_TAG}.tar.xz" \ | |
| --transform "s|^\.|LLVM-${LLVM_VERSION}-Linux-X64-${RHEL_TAG}|" \ | |
| . | |
| echo "==> Archive size: $(du -sh /output/LLVM-${LLVM_VERSION}-Linux-X64-${RHEL_TAG}.tar.xz | cut -f1)" | |
| ' | |
| - name: Upload archive as workflow artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: llvm-rhel${{ matrix.major }}-${{ inputs.llvm_version }} | |
| path: /tmp/llvm-output/LLVM-${{ inputs.llvm_version }}-Linux-X64-rhel${{ matrix.major }}.tar.xz | |
| retention-days: 3 | |
| # ── Job 2: Commit ───────────────────────────────────────────────────────────── | |
| # Separate job so a commit/push failure can be re-run in seconds without | |
| # repeating the 90-minute builds. | |
| # | |
| # Clones prebuilt directly (not via git submodule update) so it is always | |
| # on the main branch — no detached HEAD, no push ambiguity. | |
| commit: | |
| name: Commit to prebuilt/ and update submodule pointer | |
| needs: build | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| LLVM_VERSION: ${{ inputs.llvm_version }} | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| steps: | |
| - name: Checkout main repo (no submodules) | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| persist-credentials: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| submodules: false | |
| - name: Clone prebuilt on main branch | |
| run: | | |
| git clone \ | |
| "https://x-access-token:${{ secrets.PREBUILT_TOKEN }}@github.com/airgap-devkit/prebuilt.git" \ | |
| prebuilt-wr | |
| echo "prebuilt HEAD: $(git -C prebuilt-wr rev-parse HEAD)" | |
| echo "prebuilt branch: $(git -C prebuilt-wr branch --show-current)" | |
| - name: Download all LLVM archive artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: llvm-rhel*-${{ inputs.llvm_version }} | |
| merge-multiple: true | |
| path: /tmp/llvm-output/ | |
| - name: Split each variant into 50 MB parts | |
| run: | | |
| DEST="prebuilt-wr/toolchains/llvm/${LLVM_VERSION}" | |
| mkdir -p "${DEST}" | |
| for tag in rhel8 rhel9 rhel10; do | |
| SRC="/tmp/llvm-output/LLVM-${LLVM_VERSION}-Linux-X64-${tag}.tar.xz" | |
| if [[ ! -f "${SRC}" ]]; then | |
| echo " [--] ${tag}: no artifact (build skipped or failed) — leaving existing parts untouched." | |
| continue | |
| fi | |
| echo " [OK] ${tag}: splitting $(du -sh "${SRC}" | cut -f1)" | |
| rm -f "${DEST}/LLVM-${LLVM_VERSION}-Linux-X64-${tag}.tar.xz.part-"* | |
| split -b 50m "${SRC}" \ | |
| "${DEST}/LLVM-${LLVM_VERSION}-Linux-X64-${tag}.tar.xz.part-" | |
| done | |
| echo "Parts staged:" | |
| ls -lh "${DEST}/" | grep -E 'part-aa|\.json' || true | |
| - name: Commit and push prebuilt | |
| working-directory: prebuilt-wr | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add "toolchains/llvm/${LLVM_VERSION}/" | |
| git diff --cached --stat | |
| git commit -m "build: LLVM ${LLVM_VERSION} tools for RHEL/Rocky 8/9/10 (per-distro glibc builds)" | |
| git push | |
| - name: Update submodule pointer in main repo | |
| run: | | |
| PREBUILT_SHA=$(git -C prebuilt-wr rev-parse HEAD) | |
| echo "Pointing prebuilt submodule → ${PREBUILT_SHA}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git pull --rebase origin main | |
| git update-index --cacheinfo "160000,${PREBUILT_SHA},prebuilt" | |
| git commit -m "chore: update prebuilt — LLVM ${LLVM_VERSION} RHEL/Rocky 8/9/10 builds" | |
| git push |