[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