Build LLVM tools for RHEL 8 #2
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 for RHEL 8 | |
| # Builds clang, clang++, clang-format, clang-tidy, lld, llvm-ar, and llvm-nm | |
| # inside a UBI 8.10 container (glibc 2.28) and commits the result to the | |
| # prebuilt/ submodule as 50 MB split parts — matching the existing archive format. | |
| # | |
| # Two-job design: | |
| # build (~90 min) — compiles LLVM, uploads archive as a workflow artifact | |
| # commit (~10 sec) — downloads artifact, clones prebuilt on main, commits, pushes | |
| # | |
| # If only the commit step fails, use "Re-run failed jobs" — it skips the build. | |
| # | |
| # 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.4' | |
| # ── Job 1: Build ────────────────────────────────────────────────────────────── | |
| jobs: | |
| build: | |
| name: Build LLVM ${{ inputs.llvm_version }} (UBI 8.10 / glibc 2.28) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| env: | |
| LLVM_VERSION: ${{ inputs.llvm_version }} | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| # Everything below runs inside the UBI 8.10 container via docker run so | |
| # the resulting binaries are linked against glibc 2.28 and GCC 8's | |
| # libstdc++, making them compatible with any RHEL 8+ system. | |
| # | |
| # 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 RHEL 8 (glibc, libstdc++, zlib). | |
| # | |
| # cmake 3.11 (UBI 8 default) is too old for LLVM 17+; we download a | |
| # modern cmake binary from cmake.org. | |
| # | |
| # Estimated time: 80-100 minutes on a 2-CPU GitHub Actions runner. | |
| - name: Build LLVM inside UBI 8.10 container | |
| run: | | |
| mkdir -p /tmp/llvm-output | |
| docker run --rm \ | |
| --memory=6g \ | |
| --cpus="$(nproc)" \ | |
| -e LLVM_VERSION \ | |
| -v /tmp/llvm-output:/output \ | |
| registry.access.redhat.com/ubi8/ubi:8.10 \ | |
| bash -euo pipefail -c ' | |
| echo "==> System : $(cat /etc/redhat-release)" | |
| echo "==> glibc : $(ldd --version | head -1)" | |
| # ── 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 glibc 2.28..." | |
| /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-rhel8.tar.xz" \ | |
| --transform "s|^\.|LLVM-${LLVM_VERSION}-Linux-X64-rhel8|" \ | |
| . | |
| echo "==> Archive size: $(du -sh /output/LLVM-${LLVM_VERSION}-Linux-X64-rhel8.tar.xz | cut -f1)" | |
| ' | |
| - name: Upload archive as workflow artifact | |
| uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 | |
| with: | |
| name: llvm-rhel8-${{ inputs.llvm_version }} | |
| path: /tmp/llvm-output/LLVM-${{ inputs.llvm_version }}-Linux-X64-rhel8.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 build. | |
| # | |
| # 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@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| 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 LLVM archive artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: llvm-rhel8-${{ inputs.llvm_version }} | |
| path: /tmp/llvm-output/ | |
| - name: Split archive into 50 MB parts | |
| run: | | |
| DEST="prebuilt-wr/toolchains/llvm/${LLVM_VERSION}" | |
| mkdir -p "${DEST}" | |
| rm -f "${DEST}/LLVM-${LLVM_VERSION}-Linux-X64-rhel8.tar.xz.part-"* | |
| split -b 50m \ | |
| /tmp/llvm-output/LLVM-${LLVM_VERSION}-Linux-X64-rhel8.tar.xz \ | |
| "${DEST}/LLVM-${LLVM_VERSION}-Linux-X64-rhel8.tar.xz.part-" | |
| echo "Parts:" | |
| ls -lh "${DEST}/LLVM-${LLVM_VERSION}-Linux-X64-rhel8.tar.xz.part-"* | |
| - 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 8 (glibc 2.28 / UBI 8.10)" | |
| 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 update-index --cacheinfo "160000,${PREBUILT_SHA},prebuilt" | |
| git commit -m "chore: update prebuilt — LLVM ${LLVM_VERSION} RHEL 8 build" | |
| git push |