Files
ResInsight/.github/docker/Dockerfile.rhel8
T

210 lines
9.8 KiB
Docker

# syntax=docker/dockerfile:1
# =============================================================================
# RHEL8 (Rocky Linux 8) CI image for ResInsight.
#
# Bakes in:
# * The toolchain (gcc-toolset-14, libstdc++exp, Qt)
# * A prebuilt vcpkg binary cache (populated from the manifest)
# * A warm ResInsight buildcache populated by a full ResInsight-tests compile
# at the fixed path /src -> /src/cmakebuild.
#
# The CI workflow runs inside this image, checks out into /src (path must
# match the warmup so buildcache hashes line up), and only recompiles
# translation units that actually changed.
#
# Rebuilt nightly by .github/workflows/build-rhel8-image.yml.
# =============================================================================
# -----------------------------------------------------------------------------
# Stage 1: base toolchain
# -----------------------------------------------------------------------------
FROM rockylinux:8 AS base
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Base development tools and libraries.
RUN dnf install -y epel-release \
&& dnf config-manager --set-enabled powertools \
&& dnf install -y \
gcc gcc-c++ make cmake ninja-build git curl zip unzip tar \
pkgconfig perl which xz flex bison \
python39 python39-devel python39-pip \
mesa-libGL-devel mesa-libGLU-devel mesa-libEGL-devel \
libxkbcommon-devel libxkbcommon-x11-devel \
xcb-util-keysyms-devel xcb-util-image-devel xcb-util-wm-devel \
xcb-util-renderutil-devel \
fontconfig-devel freetype-devel \
libX11-devel libXext-devel libXrender-devel \
&& dnf install -y \
gcc-toolset-14 gcc-toolset-14-gcc-c++ \
gcc-toolset-14-libatomic-devel gcc-toolset-14-libstdc++-devel \
&& dnf clean all
# Build libstdc++exp from GCC source to match gcc-toolset-14.
RUN source /opt/rh/gcc-toolset-14/enable \
&& GCC_FULL_VERSION=$(gcc -dumpfullversion) \
&& GCC_MAJOR_MINOR=$(echo "$GCC_FULL_VERSION" | cut -d. -f1,2) \
&& GCC_VERSION="${GCC_MAJOR_MINOR}.0" \
&& cd /tmp \
&& curl -LO "https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.xz" \
&& tar xf "gcc-${GCC_VERSION}.tar.xz" \
&& mkdir -p "gcc-${GCC_VERSION}/build-libstdcxx" \
&& cd "gcc-${GCC_VERSION}/build-libstdcxx" \
&& ../libstdc++-v3/configure \
--prefix=/opt/libstdcxx-exp \
--disable-multilib \
--disable-libstdcxx-pch \
--with-gxx-include-dir="/opt/rh/gcc-toolset-14/root/usr/include/c++/${GCC_VERSION}" \
&& { make -k -j"$(nproc)" || true; } \
&& test -f src/experimental/.libs/libstdc++exp.a \
&& mkdir -p /opt/libstdcxx-exp/lib \
&& cp src/experimental/.libs/libstdc++exp.a /opt/libstdcxx-exp/lib/ \
&& rm -rf /tmp/gcc-*
# Python and Qt.
ARG QT_VERSION=6.6.3
RUN alternatives --set python3 /usr/bin/python3.9 \
&& python3 -m pip install --upgrade pip \
&& python3 -m pip install grpcio-tools aqtinstall \
&& python3 -m aqt install-qt linux desktop "${QT_VERSION}" gcc_64 \
-O /opt/Qt --modules qtnetworkauth
ENV Qt6_DIR=/opt/Qt/${QT_VERSION}/gcc_64 \
CMAKE_PREFIX_PATH=/opt/Qt/${QT_VERSION}/gcc_64 \
PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:${PATH}
# buildcache (pinned, built from source). When this binary is on PATH at CMake
# configure time, the project's top-level CMakeLists.txt auto-detects it via
# find_program() and wires CMAKE_CXX_COMPILER_LAUNCHER. No further CMake
# plumbing is needed.
#
# Built from source rather than downloaded because the upstream
# `buildcache-linux.tar.gz` release binary is linked against glibc 2.29+, and
# Rocky Linux 8 ships glibc 2.28 -- the binary loads but crashes the first
# time the dynamic linker touches libm. Compiling here links against the
# image's own glibc and is portable (~1-2 minutes).
# Source from GitLab -- the canonical repo. The GitHub mirror is stale (last
# tag v0.28.4, 2024-03), while GitLab has progressed to v0.33.0 with the GCC
# 14 transitive-include fixes that v0.28.x lacks.
ARG BUILDCACHE_VERSION=v0.33.0
RUN source /opt/rh/gcc-toolset-14/enable \
&& git clone --depth 1 --branch "${BUILDCACHE_VERSION}" \
https://gitlab.com/bits-n-bites/buildcache.git /tmp/buildcache-src \
&& cmake -S /tmp/buildcache-src/src -B /tmp/buildcache-build -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local \
&& cmake --build /tmp/buildcache-build --target install \
&& rm -rf /tmp/buildcache-src /tmp/buildcache-build \
&& buildcache --version
# -----------------------------------------------------------------------------
# Stage 2: populate the vcpkg binary cache
# -----------------------------------------------------------------------------
FROM base AS vcpkg-builder
ENV VCPKG_DEFAULT_BINARY_CACHE=/opt/vcpkg-cache
COPY . /src
# Running the ResInsight CMake configure triggers a vcpkg manifest install,
# which compiles every dependency into VCPKG_DEFAULT_BINARY_CACHE. The same
# toolchain is used here and in the final image, so the vcpkg ABI hashes match
# and the cache is reused by CI builds. Later configure steps may fail inside
# the build container; that is tolerated as the dependencies are already built
# by then.
#
# After configure, verify the cache contains a plausible number of entries.
# vcpkg's `files` binary provider stores one .zip per package under
# <cache>/<2-hex>/<full-hash>.zip. ResInsight depends on ~30+ packages, so a
# threshold of 20 catches the failure mode where the configure dies early
# (e.g. after building only a handful of leaf deps) while staying robust to
# small manifest churn.
RUN git config --global --add safe.directory '*' \
&& cp /src/vcpkg-configuration-rhel8.json /src/vcpkg-configuration.json \
&& mkdir -p "${VCPKG_DEFAULT_BINARY_CACHE}" \
&& source /opt/rh/gcc-toolset-14/enable \
&& ( cd /src/ThirdParty/vcpkg && ./bootstrap-vcpkg.sh ) \
&& export CC=/opt/rh/gcc-toolset-14/root/usr/bin/gcc \
&& export CXX=/opt/rh/gcc-toolset-14/root/usr/bin/g++ \
&& { cmake -S /src -B /tmp/cfg -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DRESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS=true \
-DRESINSIGHT_ENABLE_UNITY_BUILD=true \
-DRESINSIGHT_ENABLE_HDF5=false \
-DRESINSIGHT_ENABLE_GRPC=false \
-DRESINSIGHT_GCC_STDCPP_EXP_PATH=/opt/libstdcxx-exp/lib \
-DCMAKE_TOOLCHAIN_FILE=ThirdParty/vcpkg/scripts/buildsystems/vcpkg.cmake \
|| true; } \
&& vcpkg_zip_count=$(find "${VCPKG_DEFAULT_BINARY_CACHE}" -type f -name '*.zip' | wc -l) \
&& echo "vcpkg binary cache entries: ${vcpkg_zip_count}" \
&& test "${vcpkg_zip_count}" -ge 20 \
&& rm -rf /tmp/cfg /src
# -----------------------------------------------------------------------------
# Stage 3: warm the ResInsight buildcache by performing a full compile at
# /src -> /src/cmakebuild. CI runs at the same paths to get cache
# hits (buildcache hashes the absolute source path).
# -----------------------------------------------------------------------------
FROM base AS build-warmup
# Cap at 4 GB. The baked cache from this stage is what CI reads, and CI also
# writes back to the same /opt/buildcache, so the cap must be larger than
# (baked entries + per-run accumulation) or LRU eviction starts dropping baked
# entries between nightly rebuilds. 4 GB comfortably exceeds the observed
# warm cache size for a full ResInsight-tests compile.
ENV BUILDCACHE_ACCURACY=SLOPPY \
BUILDCACHE_MAX_CACHE_SIZE=4294967296
COPY --from=vcpkg-builder /opt/vcpkg-cache /opt/vcpkg-cache
COPY . /src
# The buildcache directory is mounted as a BuildKit cache mount so it persists
# across nightly image rebuilds (each rebuild only recompiles drift since the
# previous run). After the compile finishes the populated cache is copied into
# /opt/buildcache, a real path that is preserved in the image layer.
#
# Unity build is OFF here AND in the consumer workflow: with unity ON, a single
# .cpp change invalidates the whole unity blob's cache entry, defeating the
# point. The flag must match between this stage and CI or hit rate collapses
# (the command line is part of the hash).
RUN --mount=type=cache,id=ri-rhel8-buildcache,target=/var/cache/buildcache,sharing=locked \
git config --global --add safe.directory '*' \
&& cp /src/vcpkg-configuration-rhel8.json /src/vcpkg-configuration.json \
&& source /opt/rh/gcc-toolset-14/enable \
&& ( cd /src/ThirdParty/vcpkg && ./bootstrap-vcpkg.sh ) \
&& export CC=/opt/rh/gcc-toolset-14/root/usr/bin/gcc \
&& export CXX=/opt/rh/gcc-toolset-14/root/usr/bin/g++ \
&& export VCPKG_FEATURE_FLAGS=binarycaching \
&& export VCPKG_BINARY_SOURCES="clear;files,/opt/vcpkg-cache,read" \
&& export BUILDCACHE_DIR=/var/cache/buildcache \
&& cmake -S /src -B /src/cmakebuild -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DRESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS=true \
-DRESINSIGHT_ENABLE_UNITY_BUILD=false \
-DRESINSIGHT_ENABLE_HDF5=false \
-DRESINSIGHT_ENABLE_GRPC=false \
-DRESINSIGHT_GCC_STDCPP_EXP_PATH=/opt/libstdcxx-exp/lib \
-DCMAKE_TOOLCHAIN_FILE=ThirdParty/vcpkg/scripts/buildsystems/vcpkg.cmake \
&& cmake --build /src/cmakebuild --target ResInsight-tests -- -j"$(nproc)" \
&& buildcache -s \
&& mkdir -p /opt/buildcache \
&& cp -a /var/cache/buildcache/. /opt/buildcache/ \
&& test -n "$(ls -A /opt/buildcache)" \
&& rm -rf /src
# -----------------------------------------------------------------------------
# Stage 4: final image
# -----------------------------------------------------------------------------
FROM base
LABEL org.opencontainers.image.source="https://github.com/OPM/ResInsight"
LABEL org.opencontainers.image.description="RHEL8 CI image for ResInsight with prebuilt toolchain, vcpkg binary cache, and warm ResInsight buildcache"
COPY --from=vcpkg-builder /opt/vcpkg-cache /opt/vcpkg-cache
COPY --from=build-warmup /opt/buildcache /opt/buildcache
ENV VCPKG_DEFAULT_BINARY_CACHE=/opt/vcpkg-cache \
BUILDCACHE_DIR=/opt/buildcache \
BUILDCACHE_ACCURACY=SLOPPY \
BUILDCACHE_MAX_CACHE_SIZE=4294967296