[libcxx] [llvm] [libc++][CI] Add hermetic Linux premerge builder (PR #226358)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 22:13:22 PDT 2026


https://github.com/zeroomega created https://github.com/llvm/llvm-project/pull/226358

Add a hermetic Linux builder image and premerge CI job where CMake, Ninja, and Clang are installed under /opt/hermetic outside of PATH, catching implicit dependencies on host build tools or compilers in CMake or Lit test scripts (such as #224192).

- Add libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile based on ubuntu:26.04 with CMake, Ninja, and Compiler Explorer Clang installed under /opt/hermetic and no cmake/ninja/make/gcc/g++/clang in PATH.
- Register libcxx-linux-builder-hermetic in docker-compose.yml and .github/workflows/libcxx-build-containers.yml.
- Add --cmake, --ninja, --cc, and --cxx flags to libcxx/utils/ci/run-buildbot, unexporting CMAKE/NINJA/CC/CXX and passing CMAKE_C_COMPILER and CMAKE_CXX_COMPILER explicitly to CMake.
- Add a hermetic job running generic-cxx26 in .github/workflows/libcxx-pr-conformance-tests.yaml.

Assisted-by: Gemini

>From b1c74c2db4c00cd1ff26d472fd5967f7852e8a09 Mon Sep 17 00:00:00 2001
From: Haowei Wu <haowei at google.com>
Date: Thu, 24 Sep 2026 22:09:57 -0700
Subject: [PATCH] [libc++][CI] Add hermetic Linux premerge builder

Add a hermetic Linux builder image and premerge CI job where CMake,
Ninja, and Clang are installed under /opt/hermetic outside of PATH,
catching implicit dependencies on host build tools or compilers in
CMake or Lit test scripts (such as #224192).

- Add libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile based
  on ubuntu:26.04 with CMake, Ninja, and Compiler Explorer Clang
  installed under /opt/hermetic and no cmake/ninja/make/gcc/g++/clang
  in PATH.
- Register libcxx-linux-builder-hermetic in docker-compose.yml and
  .github/workflows/libcxx-build-containers.yml.
- Add --cmake, --ninja, --cc, and --cxx flags to
  libcxx/utils/ci/run-buildbot, unexporting CMAKE/NINJA/CC/CXX and
  passing CMAKE_C_COMPILER and CMAKE_CXX_COMPILER explicitly to CMake.
- Add a hermetic job running generic-cxx26 in
  .github/workflows/libcxx-pr-conformance-tests.yaml.
---
 .github/workflows/libcxx-build-containers.yml |   2 +-
 .../libcxx-pr-conformance-tests.yaml          |  35 ++++++
 libcxx/utils/ci/docker/docker-compose.yml     |  10 ++
 .../docker/linux-builder-hermetic.dockerfile  | 104 ++++++++++++++++++
 libcxx/utils/ci/run-buildbot                  |  40 ++++++-
 5 files changed, 186 insertions(+), 5 deletions(-)
 create mode 100644 libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile

diff --git a/.github/workflows/libcxx-build-containers.yml b/.github/workflows/libcxx-build-containers.yml
index 5f24cc54021ad..6cce2b239dc19 100644
--- a/.github/workflows/libcxx-build-containers.yml
+++ b/.github/workflows/libcxx-build-containers.yml
@@ -28,7 +28,7 @@ jobs:
     if: github.repository_owner == 'llvm'
     strategy:
       matrix:
-        image_name: ['libcxx-linux-builder', 'libcxx-android-builder']
+        image_name: ['libcxx-linux-builder', 'libcxx-linux-builder-hermetic', 'libcxx-android-builder']
     permissions:
       packages: write
 
diff --git a/.github/workflows/libcxx-pr-conformance-tests.yaml b/.github/workflows/libcxx-pr-conformance-tests.yaml
index 61e455e1a799d..9c09f6d373475 100644
--- a/.github/workflows/libcxx-pr-conformance-tests.yaml
+++ b/.github/workflows/libcxx-pr-conformance-tests.yaml
@@ -202,6 +202,41 @@ jobs:
             **/CMakeOutput.log
             **/crash_diagnostics/*
 
+  hermetic:
+    if: github.repository_owner == 'llvm'
+    runs-on: llvm-premerge-linux-32-runners
+    container:
+      image: ghcr.io/llvm/libcxx-linux-builder-hermetic:d79f222aea61926e7c81fa8908b12f52ea70111f
+    needs: [ stage2 ]
+    continue-on-error: false
+    steps:
+      - uses: actions/checkout at df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+        with:
+          persist-credentials: false
+      - name: generic-cxx26 (hermetic)
+        shell: bash
+        run: |
+          python3 -m venv --system-site-packages .venv
+          source .venv/bin/activate
+          pip install -r libcxx/test/requirements.txt
+          libcxx/utils/ci/run-buildbot \
+            --cmake /opt/hermetic/cmake/bin/cmake \
+            --ninja /opt/hermetic/ninja/ninja \
+            --cc /opt/hermetic/llvm/bin/clang \
+            --cxx /opt/hermetic/llvm/bin/clang++ \
+            generic-cxx26
+      - uses: actions/upload-artifact at 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+        if: always()
+        with:
+          name: generic-cxx26-hermetic-results
+          path: |
+            **/test-results.xml
+            **/*.abilist
+            **/CMakeConfigureLog.yaml
+            **/CMakeError.log
+            **/CMakeOutput.log
+            **/crash_diagnostics/*
+
   macos:
     needs: [ stage2 ]
     strategy:
diff --git a/libcxx/utils/ci/docker/docker-compose.yml b/libcxx/utils/ci/docker/docker-compose.yml
index 2070dcd96274c..e2280af3d6ab8 100644
--- a/libcxx/utils/ci/docker/docker-compose.yml
+++ b/libcxx/utils/ci/docker/docker-compose.yml
@@ -17,6 +17,16 @@ services:
         GCC_HEAD_VERSION: 17
         LLVM_HEAD_VERSION: 23
 
+  libcxx-linux-builder-hermetic:
+    image: ghcr.io/llvm/libcxx-linux-builder-hermetic:${TAG:-latest}
+    build:
+      context: ../../../.. # monorepo root
+      dockerfile: libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile
+      args:
+        LLVM_HEAD_VERSION: 23
+        CMAKE_VERSION: 4.4.3
+        NINJA_VERSION: 1.13.2
+
   libcxx-android-builder:
     image: ghcr.io/llvm/libcxx-android-builder:${TAG:-latest}
     build:
diff --git a/libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile b/libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile
new file mode 100644
index 0000000000000..792195137c0fe
--- /dev/null
+++ b/libcxx/utils/ci/docker/linux-builder-hermetic.dockerfile
@@ -0,0 +1,104 @@
+# ===----------------------------------------------------------------------===##
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+# ===----------------------------------------------------------------------===##
+#
+# This file defines the hermetic Linux builder image used for libc++ CI testing
+# where CMake, Ninja, and Clang/LLVM are placed under /opt/hermetic outside of
+# PATH, catching any implicit dependencies on host build tools or compilers.
+#
+# From the root of the monorepo, this image can be built with:
+#
+#   $ docker compose --file libcxx/utils/ci/docker/docker-compose.yml build libcxx-linux-builder-hermetic
+#
+
+FROM docker.io/library/ubuntu:26.04
+
+# Changing this file causes a rebuild of the image in a GitHub action.
+RUN echo "Last forced update executed on 2026-09-24."
+
+# Make sure apt-get doesn't try to prompt for stuff like our time zone, etc.
+ENV DEBIAN_FRONTEND=noninteractive
+
+# Populated in the docker-compose file
+ARG LLVM_HEAD_VERSION=23
+ENV LLVM_HEAD_VERSION=${LLVM_HEAD_VERSION}
+
+ARG CMAKE_VERSION=4.4.3
+ENV CMAKE_VERSION=${CMAKE_VERSION}
+
+ARG NINJA_VERSION=1.13.2
+ENV NINJA_VERSION=${NINJA_VERSION}
+
+# Install sudo and setup passwordless sudo.
+RUN apt-get update && \
+    apt-get install -y sudo && \
+    echo "ALL ALL = (ALL) NOPASSWD: ALL" | tee /etc/sudoers
+
+# Installing tzdata before other packages avoids the time zone prompts.
+RUN sudo apt-get update \
+    && sudo apt-get install -y \
+        tzdata
+
+# Install runtime/test utilities and the basic host C sysroot (libc6-dev, libgcc-15-dev).
+# Intentionally OMIT: build-essential, gcc, g++, clang, make, cmake, ninja-build.
+RUN sudo apt-get update \
+    && sudo apt-get install -y \
+        bash \
+        binutils \
+        bzip2 \
+        curl \
+        gdb \
+        git \
+        gpg \
+        language-pack-en \
+        language-pack-fr \
+        language-pack-ja \
+        language-pack-ru \
+        language-pack-zh-hans \
+        libc6-dev \
+        libgcc-15-dev \
+        libstdc++-15-dev \
+        lsb-release \
+        python3 \
+        python3-dev \
+        python3-packaging \
+        python3-psutil \
+        python3-setuptools \
+        python3-venv \
+        python3-yaml \
+        rsync \
+        unzip \
+        wget \
+        xz-utils \
+    && sudo rm -rf /var/lib/apt/lists/*
+
+# These two locales are not enabled by default so generate them
+RUN printf "fr_CA ISO-8859-1\ncs_CZ ISO-8859-2\n" | sudo tee -a /etc/locale.gen && \
+    sudo mkdir -p /usr/local/share/i1en/ && \
+    printf "fr_CA ISO-8859-1\ncs_CZ ISO-8859-2\n" | sudo tee -a /usr/local/share/i1en/SUPPORTED && \
+    sudo locale-gen
+
+# Fetch CMake and Ninja from official GitHub releases, and Clang from Compiler Explorer
+# (matching linux-builder.dockerfile's ce_install and LLVM_HEAD_VERSION), into /opt/hermetic
+# outside of PATH.
+RUN sudo mkdir -p /opt/hermetic/cmake /opt/hermetic/ninja && \
+    curl -fsSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz" \
+      | sudo tar xzf - --strip-components=1 -C /opt/hermetic/cmake && \
+    curl -fsSL -o /tmp/ninja-linux.zip \
+      "https://github.com/ninja-build/ninja/releases/download/v${NINJA_VERSION}/ninja-linux.zip" && \
+    sudo unzip -q /tmp/ninja-linux.zip -d /opt/hermetic/ninja && \
+    sudo chmod +x /opt/hermetic/ninja/ninja && \
+    rm -f /tmp/ninja-linux.zip && \
+    sudo apt-get update && sudo apt-get install -y make && \
+    sudo git clone --depth 1 https://github.com/compiler-explorer/infra.git /tmp/ce-infra && \
+    (cd /tmp/ce-infra && sudo make ce) && \
+    sudo /tmp/ce-infra/bin/ce_install --dest /opt/hermetic --enable nightly install compilers/c++/nightly/clang trunk && \
+    sudo ln -sfn /opt/hermetic/clang-trunk /opt/hermetic/llvm && \
+    sudo ln -sfn /opt/hermetic/clang-trunk/bin/clang /opt/hermetic/llvm/bin/clang-${LLVM_HEAD_VERSION} && \
+    sudo ln -sfn /opt/hermetic/clang-trunk/bin/clang++ /opt/hermetic/llvm/bin/clang++-${LLVM_HEAD_VERSION} && \
+    sudo rm -rf /tmp/ce-infra && \
+    sudo apt-get purge -y make && sudo apt-get autoremove -y && sudo rm -rf /var/lib/apt/lists/*
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index 572f326c4fb0a..ed49ada7a601a 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -28,6 +28,14 @@ ${PROGNAME} [options] <BUILDER>
 --build-dir <DIR>   The directory to use for building the library. By default,
                     this is '<llvm-root>/build/<builder>'.
 
+--cmake <PATH>      Path to the cmake binary to use.
+
+--ninja <PATH>      Path to the ninja binary to use.
+
+--cc <PATH>         Path to the C compiler to use.
+
+--cxx <PATH>        Path to the C++ compiler to use.
+
 Environment variables
 CMAKE               The cmake binary to use. This variable is optional.
 
@@ -89,6 +97,22 @@ while [[ $# -gt 0 ]]; do
             BUILD_DIR="${2}"
             shift; shift
             ;;
+        --cmake)
+            CMAKE="${2}"
+            shift; shift
+            ;;
+        --ninja)
+            NINJA="${2}"
+            shift; shift
+            ;;
+        --cc)
+            CC="${2}"
+            shift; shift
+            ;;
+        --cxx)
+            CXX="${2}"
+            shift; shift
+            ;;
         *)
             BUILDER="${1}"
             shift
@@ -111,15 +135,19 @@ else
 fi
 
 if [ -z ${CC+x} ]; then
-    error "Environment variable CC must be defined"
+    error "Environment variable CC or --cc must be defined"
     exit 1
 fi
 
 if [ -z ${CXX+x} ]; then
-    error "Environment variable CXX must be defined"
+    error "Environment variable CXX or --cxx must be defined"
     exit 1
 fi
 
+# Un-export tool variables from the environment so child processes (such as Lit)
+# do not implicitly rely on environment variables instead of CMake substitutions.
+export -n CMAKE NINJA CC CXX
+
 # Print the version of a few tools to aid diagnostics in some cases
 step "Diagnose tools in use"
 ${CMAKE} --version
@@ -135,8 +163,10 @@ function generate-cmake-base() {
     step "Generating CMake"
 
     # FIXME: This should really be set in the Dockerfile
-    export CMAKE_PREFIX_PATH="/opt/compiler-explorer/clang-trunk/lib/cmake"
-    export PATH="$PATH:/opt/compiler-explorer/clang-trunk/bin"
+    if [ -d "/opt/compiler-explorer/clang-trunk/bin" ]; then
+        export CMAKE_PREFIX_PATH="/opt/compiler-explorer/clang-trunk/lib/cmake"
+        export PATH="$PATH:/opt/compiler-explorer/clang-trunk/bin"
+    fi
 
     # We can remove -DCMAKE_INSTALL_MESSAGE=NEVER once https://gitlab.kitware.com/cmake/cmake/-/issues/26085 is fixed.
     ${CMAKE} \
@@ -144,6 +174,8 @@ function generate-cmake-base() {
           -B "${BUILD_DIR}" \
           -GNinja \
           ${MAKE_PROGRAM} \
+          -DCMAKE_C_COMPILER="${CC}" \
+          -DCMAKE_CXX_COMPILER="${CXX}" \
           -DCMAKE_BUILD_TYPE=RelWithDebInfo \
           -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
           -DLIBCXX_ENABLE_WERROR=YES \



More information about the llvm-commits mailing list