diff --git a/.github/workflows/build-container.yml b/.github/workflows/build-container.yml index 67df008c220df..24fa92165a1d0 100644 --- a/.github/workflows/build-container.yml +++ b/.github/workflows/build-container.yml @@ -3,6 +3,10 @@ name: Build container on: workflow_call: inputs: + build-contexts: + description: "Paths to additional build contexts" + required: false + type: string context: description: "Path to use for build context" required: true @@ -56,6 +60,7 @@ jobs: with: context: ${{ inputs.context }} file: ${{ inputs.file }} + build-contexts: ${{ inputs.build-contexts }} push: true tags: | ghcr.io/${{ steps.prepare.outputs.repo }}/${{ inputs.name }}:${{ hashFiles(inputs.file) }} diff --git a/.github/workflows/build-depends.yml b/.github/workflows/build-depends.yml index b2fefcba010cd..b580926e0724c 100644 --- a/.github/workflows/build-depends.yml +++ b/.github/workflows/build-depends.yml @@ -80,6 +80,7 @@ jobs: export HOST="${{ steps.setup.outputs.HOST }}" if [ "${HOST}" = "x86_64-apple-darwin" ]; then ./contrib/containers/guix/scripts/setup-sdk + unset LIBRARY_PATH LD_LIBRARY_PATH fi env ${{ steps.setup.outputs.DEP_OPTS }} make -j$(nproc) -C depends diff --git a/.github/workflows/build-src.yml b/.github/workflows/build-src.yml index 6f9d3279b845b..3c811ed297f4b 100644 --- a/.github/workflows/build-src.yml +++ b/.github/workflows/build-src.yml @@ -82,6 +82,9 @@ jobs: BASE_OUTDIR="/output" BUILD_TARGET="${{ inputs.build-target }}" source ./ci/dash/matrix.sh + if [ "${HOST}" = "x86_64-apple-darwin" ]; then + unset LIBRARY_PATH LD_LIBRARY_PATH + fi ./ci/dash/build_src.sh ccache -X 9 ccache -c @@ -108,6 +111,8 @@ jobs: run: | export BUILD_TARGET="${{ inputs.build-target }}" export BUNDLE_KEY="build-${BUILD_TARGET}-$(git rev-parse --short=8 HEAD)" + export BASE_DIR="$(pwd)" + ./ci/dash/build_patch.sh ./ci/dash/bundle-artifacts.sh create echo "key=${BUNDLE_KEY}" >> "${GITHUB_OUTPUT}" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4e9b6c9efa8b1..72143344bc588 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,6 +46,8 @@ jobs: context: ./contrib/containers/ci file: ./contrib/containers/ci/ci.Dockerfile name: dashcore-ci-runner + build-contexts: | + docker_root=./contrib/containers/ci container-slim: name: Build slim container diff --git a/ci/dash/build_patch.sh b/ci/dash/build_patch.sh new file mode 100755 index 0000000000000..9d41d004dd1cc --- /dev/null +++ b/ci/dash/build_patch.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# Copyright (c) 2025 The Dash Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +set -eo pipefail + +SH_NAME="$(basename "${0}")" + +if [ -z "${BASE_DIR}" ]; then + echo "${SH_NAME}: BASE_DIR not defined, cannot continue!"; + exit 1; +elif [ -z "${BUILD_TARGET}" ]; then + echo "${SH_NAME}: BUILD_TARGET not defined, cannot continue!"; + exit 1; +elif [ ! "$(command -v uname)" ]; then + echo "${SH_NAME}: uname not found, cannot continue!"; + exit 1; +elif [ ! "$(command -v patchelf)" ]; then + echo "${SH_NAME}: patchelf not found, cannot continue!"; + exit 1; +elif [ ! -d "${BASE_DIR}/build-ci/dashcore-${BUILD_TARGET}/src" ]; then + echo "${SH_NAME}: cannot find directory for binaries to patch, cannot continue!"; + exit 1; +fi + +# uname -m | interpreter +# -------- | ----------------------------- +# aarch64 | /lib/ld-linux-aarch64.so.1 +# armhf | /lib/ld-linux-armhf.so.3 +# i686 | /lib/ld-linux.so.2 +# riscv64 | /lib/ld-linux-riscv64-lp64d.so.1 +# x86_64 | /lib64/ld-linux-x86-64.so.2 + +INTERPRETER="" +case "${BUILD_TARGET}" in + "linux64_nowallet" | "linux64_sqlite") + INTERPRETER="/lib64/ld-linux-x86-64.so.2"; + ;; + *) + echo "${SH_NAME}: Nothing to do, exiting!"; + exit 0; + ;; +esac + +BINARIES=( + "dashd" + "dash-cli" + "dash-gui" + "dash-node" + "dash-tx" + "dash-wallet" + "bench/bench_dash" + "qt/dash-qt" + "qt/test/test_dash-qt" + "test/test_dash" + "test/fuzz/fuzz" +) + +for target in "${BINARIES[@]}" +do + target_path="${BASE_DIR}/build-ci/dashcore-${BUILD_TARGET}/src/${target}" + if [[ -f "${target_path}" ]]; then + patchelf --set-interpreter "${INTERPRETER}" "${target_path}"; + fi +done diff --git a/ci/test/00_setup_env_native_nowallet.sh b/ci/test/00_setup_env_native_nowallet.sh index 3637d3b8d0dab..094697d0ef108 100755 --- a/ci/test/00_setup_env_native_nowallet.sh +++ b/ci/test/00_setup_env_native_nowallet.sh @@ -9,6 +9,6 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_nowallet export HOST=x86_64-pc-linux-gnu export PACKAGES="python3-zmq" -export DEP_OPTS="NO_WALLET=1 CC=gcc-14 CXX=g++-14" +export DEP_OPTS="NO_WALLET=1 CC=gcc-15 CXX=g++-15" export GOAL="install" -export BITCOIN_CONFIG="--enable-reduce-exports --with-boost-process CC=gcc-14 CXX=g++-14" +export BITCOIN_CONFIG="--enable-reduce-exports --with-boost-process CC=gcc-15 CXX=g++-15" diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh index a2ff43d07e02f..405363f942d58 100755 --- a/ci/test/00_setup_env_native_qt5.sh +++ b/ci/test/00_setup_env_native_qt5.sh @@ -9,10 +9,10 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_qt5 export HOST=x86_64-pc-linux-gnu export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev" -export DEP_OPTS="" +export DEP_OPTS="CC=gcc-11 CXX=g++-11" export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_pruning,feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash export RUN_UNIT_TESTS_SEQUENTIAL="true" export RUN_UNIT_TESTS="false" export GOAL="install" export DOWNLOAD_PREVIOUS_RELEASES="true" -export BITCOIN_CONFIG="--enable-zmq --with-libs=no --enable-reduce-exports LDFLAGS=-static-libstdc++ --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --with-libs=no --enable-reduce-exports LDFLAGS=-static-libstdc++ --with-boost-process CC=gcc CXX=g++" diff --git a/contrib/containers/ci/ci-slim.Dockerfile b/contrib/containers/ci/ci-slim.Dockerfile index 4abab253573fa..bb459297ba669 100644 --- a/contrib/containers/ci/ci-slim.Dockerfile +++ b/contrib/containers/ci/ci-slim.Dockerfile @@ -45,6 +45,7 @@ RUN set -ex; \ libsqlite3-dev \ libssl-dev \ make \ + patchelf \ xz-utils \ zlib1g-dev \ zstd \ diff --git a/contrib/containers/ci/ci.Dockerfile b/contrib/containers/ci/ci.Dockerfile index c454bc7cd6834..1963b5d8d5a98 100644 --- a/contrib/containers/ci/ci.Dockerfile +++ b/contrib/containers/ci/ci.Dockerfile @@ -18,8 +18,6 @@ RUN set -ex; \ bsdmainutils \ ccache \ cmake \ - g++-11 \ - g++-14 \ g++-arm-linux-gnueabihf \ g++-mingw-w64-x86-64 \ gawk \ @@ -67,6 +65,46 @@ RUN set -ex; \ make install -j "$(( $(nproc) - 1 ))"; \ cd /opt && rm -rf /opt/iwyu; +# Install Nix to fetch versioned GCC releases +RUN set -ex; \ + curl -fsSL https://install.determinate.systems/nix | sh -s -- install linux \ + --determinate \ + --extra-conf "sandbox = false" \ + --no-confirm \ + --init none +ENV PATH="/nix/var/nix/profiles/default/bin:${PATH}" \ + NIX_CONF_DIR="/etc/nix" +COPY --from=docker_root ./nix.custom.conf /etc/nix/nix.custom.conf +COPY --from=docker_root ./default.nix /etc/nix/ +RUN set -ex; \ + nix-env -f /etc/nix/default.nix -i; \ + nix-collect-garbage -d; \ + nix-store --optimise; +RUN set -ex; \ + chmod -R o+rX /nix/store /nix/var/nix/profiles/default; \ + mkdir -p /usr/local/bin /usr/local/lib /usr/local/lib64; \ + for bin in /nix/var/nix/profiles/default/bin/*; do \ + if [ -f "$bin" ]; then \ + ln -sf "$bin" "/usr/local/bin/$(basename "$bin")"; \ + fi; \ + done; \ + for dir in /nix/var/nix/profiles/default/lib/*; do \ + if [ -d "$dir" ]; then \ + ln -sf "$dir" "/usr/local/lib/$(basename "$dir")"; \ + fi; \ + done; \ + for dir in /nix/var/nix/profiles/default/lib64/*; do \ + if [ -d "$dir" ]; then \ + ln -sf "$dir" "/usr/local/lib64/$(basename "$dir")"; \ + fi; \ + done; \ + ln -sf "/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)" "/usr/lib/multiarch" +# Nix-supplied compilers won't search for distro-installed libraries without explicit +# specification and we can't run binaries built with those compilers without specifying +# where their runtime dependencies are +ENV LD_LIBRARY_PATH="/usr/local/lib64/gcc-15:/usr/local/lib/gcc-15:/usr/local/lib64/gcc-11:/usr/local/lib/gcc-11:${LD_LIBRARY_PATH}" +ENV LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/lib/multiarch:/usr/lib" + RUN \ mkdir -p /cache/ccache && \ mkdir /cache/depends && \ diff --git a/contrib/containers/ci/default.nix b/contrib/containers/ci/default.nix new file mode 100644 index 0000000000000..4b66e89a4a82e --- /dev/null +++ b/contrib/containers/ci/default.nix @@ -0,0 +1,86 @@ +let + pkgsLegacy = import (builtins.fetchTarball { + name = "nixos-23.11"; + url = "https://github.com/NixOS/nixpkgs/archive/23.11.tar.gz"; + sha256 = "sha256-MxCVrXY6v4QmfTwIysjjaX0XUhqBbxTWWB4HXtDYsdk="; + }) {}; + + pkgsUnstable = import (builtins.fetchTarball { + name = "nixos-unstable"; + url = "https://github.com/NixOS/nixpkgs/archive/85a6c4a07faa12aaccd81b36ba9bfc2bec974fa1.tar.gz"; + sha256 = "sha256-3YJkOBrFpmcusnh7i8GXXEyh7qZG/8F5z5+717550Hk="; + }) {}; +in +pkgsUnstable.buildEnv { + name = "nixEnv"; + ignoreCollisions = true; + paths = [ + pkgsLegacy.gcc11 + pkgsUnstable.gcc15 + ]; + + postBuild = '' + binaries=( + addr2line + ar + as + c++ + c++filt + cc + cpp + dwp + elfedit + g++ + gcc + gcc-ar + gcc-nm + gcc-ranlib + gccgo + gcov + gcov-dump + gcov-tool + gdc + gfortran + gprof + ld + ld.bfd + ld.gold + lto-dump + nm + objcopy + objdump + ranlib + readelf + size + strings + strip + ) + + target_triple="${pkgsUnstable.stdenv.targetPlatform.config}" + for binary in "''${binaries[@]}"; do + if [ -f "${pkgsLegacy.gcc11}/bin/$binary" ]; then + ln -sf "${pkgsLegacy.gcc11}/bin/$binary" "$out/bin/$binary-11" + ln -sf "${pkgsLegacy.gcc11}/bin/$binary" "$out/bin/$target_triple-$binary-11" + fi + if [ -f "${pkgsUnstable.gcc15}/bin/$binary" ]; then + ln -sf "${pkgsUnstable.gcc15}/bin/$binary" "$out/bin/$binary-15" + ln -sf "${pkgsUnstable.gcc15}/bin/$binary" "$out/bin/$target_triple-$binary-15" + fi + rm -f "$out/bin/$binary" + done + + mkdir -p $out/lib $out/lib64 + if [ -d "${pkgsLegacy.gcc11.cc.lib}/lib" ]; then + ln -sf "${pkgsLegacy.gcc11.cc.lib}/lib" "$out/lib/gcc-11" + fi + if [ -d "${pkgsLegacy.gcc11.cc.lib}/lib64" ]; then + ln -sf "${pkgsLegacy.gcc11.cc.lib}/lib64" "$out/lib64/gcc-11" + fi + if [ -d "${pkgsUnstable.gcc15.cc.lib}/lib" ]; then + ln -sf "${pkgsUnstable.gcc15.cc.lib}/lib" "$out/lib/gcc-15" + fi + if [ -d "${pkgsUnstable.gcc15.cc.lib}/lib64" ]; then + ln -sf "${pkgsUnstable.gcc15.cc.lib}/lib64" "$out/lib64/gcc-15" + fi + ''; +} diff --git a/contrib/containers/ci/nix.custom.conf b/contrib/containers/ci/nix.custom.conf new file mode 100644 index 0000000000000..75bca563af946 --- /dev/null +++ b/contrib/containers/ci/nix.custom.conf @@ -0,0 +1,15 @@ +experimental-features = auto-allocate-uids flakes nix-command + +# Space optimization +auto-optimise-store = true + +# Builder settings for CI +auto-allocate-uids = true +cores = 0 +max-jobs = auto + +# Binary caches for faster downloads +accept-flake-config = true +substituters = https://cache.nixos.org https://nix-community.cachix.org +trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= +max-substitution-jobs = 0 diff --git a/contrib/containers/develop/Dockerfile b/contrib/containers/develop/Dockerfile index 90694d7e443eb..334a706b2f6b6 100644 --- a/contrib/containers/develop/Dockerfile +++ b/contrib/containers/develop/Dockerfile @@ -28,7 +28,6 @@ RUN set -ex; \ openssh-client \ screen \ sudo \ - zsh \ && \ rm -rf /var/lib/apt/lists/* diff --git a/contrib/containers/develop/docker-compose.yml b/contrib/containers/develop/docker-compose.yml index c6f2cea704243..39238d6d4d0c8 100644 --- a/contrib/containers/develop/docker-compose.yml +++ b/contrib/containers/develop/docker-compose.yml @@ -4,6 +4,8 @@ services: build: context: '..' dockerfile: './develop/Dockerfile' + additional_contexts: + - docker_root=../ci args: USER_ID: 1000 # set this to $(id -u) of the host GROUP_ID: 1000 # set this to $(id -g) of the host