From 092c0d70031e702aa1eb6abc5af0eb56309264c3 Mon Sep 17 00:00:00 2001 From: will Date: Mon, 23 Feb 2026 11:26:42 +0000 Subject: [PATCH 01/12] add patchelf-releases devShell command Patches dynamically linked ELF binaries under $PREVIOUS_RELEASES_DIR to use the Nix glibc interpreter, so previous Bitcoin Core releases can run on NixOS. --- flake.nix | 20 ++++++++++++++++++++ scripts/patchelf-releases.sh | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 scripts/patchelf-releases.sh diff --git a/flake.nix b/flake.nix index fcf531c..f1bf075 100644 --- a/flake.nix +++ b/flake.nix @@ -57,6 +57,20 @@ } ''; + patchelf-releases = pkgs.writeShellApplication { + name = "patchelf-releases"; + runtimeInputs = with pkgs; [ + patchelf + file + findutils + gnugrep + ]; + text = builtins.replaceStrings + [ "@interp@" ] + [ "${pkgs.glibc}/lib/ld-linux-x86-64.so.2" ] + (builtins.readFile ./scripts/patchelf-releases.sh); + }; + stdEnv = let llvmStdenv = @@ -137,8 +151,14 @@ pkgs.ruff pkgs.ty pythonEnv + # vouch + pkgs.gh + pkgs.nodePackages.prettier + pkgs.nushell + pkgs.pinact ] ++ lib.optionals isLinux [ + patchelf-releases pkgs.gdb pkgs.valgrind ] diff --git a/scripts/patchelf-releases.sh b/scripts/patchelf-releases.sh new file mode 100644 index 0000000..8644216 --- /dev/null +++ b/scripts/patchelf-releases.sh @@ -0,0 +1,24 @@ +INTERP="@interp@" + +if [ -z "${PREVIOUS_RELEASES_DIR:-}" ]; then + echo "error: PREVIOUS_RELEASES_DIR is not set" >&2 + exit 1 +fi + +if [ ! -f "$INTERP" ]; then + echo "error: interpreter not found: $INTERP" >&2 + exit 1 +fi + +echo "Using interpreter: $INTERP" + +count=0 +while IFS= read -r -d '' bin; do + if file "$bin" | grep -q 'ELF.*dynamically linked'; then + patchelf --set-interpreter "$INTERP" "$bin" + echo " patched: ${bin#"$PREVIOUS_RELEASES_DIR"/}" + count=$((count + 1)) + fi +done < <(find "$PREVIOUS_RELEASES_DIR" -path '*/bin/*' -type f -print0) + +echo "Patched $count binaries." From 1775080ce72e94752e805507c5e5bda61c295416 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 09:43:39 +0000 Subject: [PATCH 02/12] configure mold adapter correctly on linux --- flake.lock | 6 +++--- flake.nix | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 6714924..48aa465 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1768886240, - "narHash": "sha256-C2TjvwYZ2VDxYWeqvvJ5XPPp6U7H66zeJlRaErJKoEM=", + "lastModified": 1773122722, + "narHash": "sha256-FIqHByVqxCprNjor1NqF80F2QQoiiyqanNNefdlvOg4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "80e4adbcf8992d3fd27ad4964fbb84907f9478b0", + "rev": "62dc67aa6a52b4364dd75994ec00b51fbf474e50", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index f1bf075..5be338a 100644 --- a/flake.nix +++ b/flake.nix @@ -83,10 +83,10 @@ else llvmPackages.stdenv; in - if isLinux then - pkgs.stdenvAdapters.useMoldLinker (pkgs.ccacheStdenv.override { stdenv = llvmStdenv; }) - else - pkgs.ccacheStdenv.override { stdenv = llvmStdenv; }; + let + moldStdenv = if isLinux then pkgs.stdenvAdapters.useMoldLinker llvmStdenv else llvmStdenv; + in + pkgs.ccacheStdenv.override { stdenv = moldStdenv; }; pythonEnv = python.withPackages ( ps: From ac9b503ee58477978c99699b55e2d8f7a9eb8cdd Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 09:43:58 +0000 Subject: [PATCH 03/12] add doxygen --- flake.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 5be338a..d0e438d 100644 --- a/flake.nix +++ b/flake.nix @@ -86,7 +86,7 @@ let moldStdenv = if isLinux then pkgs.stdenvAdapters.useMoldLinker llvmStdenv else llvmStdenv; in - pkgs.ccacheStdenv.override { stdenv = moldStdenv; }; + pkgs.ccacheStdenv.override { stdenv = moldStdenv; }; pythonEnv = python.withPackages ( ps: @@ -146,6 +146,7 @@ packages = [ clang-tidy-diff pkgs.codespell + pkgs.doxygen pkgs.hexdump pkgs.include-what-you-use pkgs.ruff From 0b293774c6f1ea034d04b98e8b81f197fbe89100 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 10:04:21 +0000 Subject: [PATCH 04/12] remove Qt from shell this amount of shit this adds to -isystem paths bloats link speed to over 300ms per invocation, which slows configure down a lot. --- .github/workflows/nix.yml | 1 + flake.nix | 17 ++--------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 61120cb..5331528 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -94,6 +94,7 @@ jobs: -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ --preset dev-mode \ + -DBUILD_GUI=OFF \ ${{ matrix.cmake_flags }} cmake --build build -j${{ matrix.cores }} ccache --show-stats diff --git a/flake.nix b/flake.nix index d0e438d..5e2ded3 100644 --- a/flake.nix +++ b/flake.nix @@ -122,17 +122,11 @@ pkgs.linuxPackages.bpftrace ]; - qtBuildInputs = [ - pkgs.qt6.qtbase # https://nixos.org/manual/nixpkgs/stable/#sec-language-qt - pkgs.qt6.qttools - ]; - # Will exist in the runtime environment buildInputs = [ pkgs.boost pkgs.capnproto pkgs.libevent - pkgs.qrencode pkgs.sqlite.dev pkgs.zeromq ]; @@ -152,11 +146,6 @@ pkgs.ruff pkgs.ty pythonEnv - # vouch - pkgs.gh - pkgs.nodePackages.prettier - pkgs.nushell - pkgs.pinact ] ++ lib.optionals isLinux [ patchelf-releases @@ -172,10 +161,8 @@ }; in { - devShells.default = mkDevShell nativeBuildInputs ( - buildInputs ++ qtBuildInputs ++ [ pkgs.qt6.wrapQtAppsHook ] - ); - devShells.depends = (mkDevShell nativeBuildInputs qtBuildInputs).overrideAttrs (oldAttrs: { + devShells.default = mkDevShell nativeBuildInputs buildInputs; + devShells.depends = (mkDevShell nativeBuildInputs).overrideAttrs (oldAttrs: { # Set these to force depends capnp to also use clang, otherwise it # fails when looking for the default (gcc/g++) build_CC = "clang"; From 149cf44473c06b97416485b6a6795d1d26d1337b Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 10:05:03 +0000 Subject: [PATCH 05/12] nix fmt --- flake.nix | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 5e2ded3..499beff 100644 --- a/flake.nix +++ b/flake.nix @@ -65,10 +65,9 @@ findutils gnugrep ]; - text = builtins.replaceStrings - [ "@interp@" ] - [ "${pkgs.glibc}/lib/ld-linux-x86-64.so.2" ] - (builtins.readFile ./scripts/patchelf-releases.sh); + text = builtins.replaceStrings [ "@interp@" ] [ "${pkgs.glibc}/lib/ld-linux-x86-64.so.2" ] ( + builtins.readFile ./scripts/patchelf-releases.sh + ); }; stdEnv = @@ -162,7 +161,7 @@ in { devShells.default = mkDevShell nativeBuildInputs buildInputs; - devShells.depends = (mkDevShell nativeBuildInputs).overrideAttrs (oldAttrs: { + devShells.depends = (mkDevShell nativeBuildInputs [ ]).overrideAttrs (oldAttrs: { # Set these to force depends capnp to also use clang, otherwise it # fails when looking for the default (gcc/g++) build_CC = "clang"; From 665cc976988bc4c8a42cca20bb509e2488cc73e3 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 10:10:28 +0000 Subject: [PATCH 06/12] remove vulture --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 499beff..8c7f117 100644 --- a/flake.nix +++ b/flake.nix @@ -97,7 +97,6 @@ pyzmq pycapnp requests - vulture ] ++ lib.optionals isLinux [ bcc From ccf479e5388f7df9428f8bd4df29f0390c6f0039 Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 11:01:26 +0000 Subject: [PATCH 07/12] use aarch64 macos runners --- .github/workflows/nix.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 5331528..1a5d23d 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -28,8 +28,8 @@ jobs: cores: 4 cmake_flags: - system: x86_64-darwin - runner_label: macos-15-intel - cores: 4 + runner_label: macos-latest + cores: 3 cmake_flags: -DWITH_USDT=OFF - system: aarch64-darwin runner_label: macos-latest From 485e4cb40cdddc58742c33bf6cfe75d7d4e3616f Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 11:12:16 +0000 Subject: [PATCH 08/12] remove capnp overlay, and simplify depends devShell We can use the regular shell to build depends just fine. --- flake.lock | 6 +++--- flake.nix | 25 +++++-------------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/flake.lock b/flake.lock index 48aa465..8b5984e 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1773122722, - "narHash": "sha256-FIqHByVqxCprNjor1NqF80F2QQoiiyqanNNefdlvOg4=", + "lastModified": 1773734432, + "narHash": "sha256-IF5ppUWh6gHGHYDbtVUyhwy/i7D261P7fWD1bPefOsw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "62dc67aa6a52b4364dd75994ec00b51fbf474e50", + "rev": "cda48547b432e8d3b18b4180ba07473762ec8558", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 8c7f117..39301b9 100644 --- a/flake.nix +++ b/flake.nix @@ -17,20 +17,6 @@ let pkgs = import nixpkgs { inherit system; - overlays = [ - (final: prev: { - capnproto = prev.capnproto.overrideAttrs (oldAttrs: rec { - version = "1.3.0"; - src = prev.fetchFromGitHub { - owner = "capnproto"; - repo = "capnproto"; - rev = "v${version}"; - hash = "sha256-fvZzNDBZr73U+xbj1LhVj1qWZyNmblKluh7lhacV+6I="; - }; - patches = [ ]; - }); - }) - ]; }; inherit (pkgs) lib; inherit (pkgs.stdenv) isLinux isDarwin; @@ -156,16 +142,15 @@ CMAKE_EXPORT_COMPILE_COMMANDS = 1; LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.capnproto ]; LOCALE_ARCHIVE = lib.optionalString isLinux "${pkgs.glibcLocales}/lib/locale/locale-archive"; + # Force depends capnp to also use clang, otherwise it fails when + # looking for the default (gcc/g++) + build_CC = "clang"; + build_CXX = "clang++"; }; in { devShells.default = mkDevShell nativeBuildInputs buildInputs; - devShells.depends = (mkDevShell nativeBuildInputs [ ]).overrideAttrs (oldAttrs: { - # Set these to force depends capnp to also use clang, otherwise it - # fails when looking for the default (gcc/g++) - build_CC = "clang"; - build_CXX = "clang++"; - }); + devShells.depends = mkDevShell nativeBuildInputs [ ]; formatter = pkgs.nixfmt-tree; } ); From 38faddeab880507cd2ea6d47a5081e7db4b5d39f Mon Sep 17 00:00:00 2001 From: will Date: Wed, 18 Mar 2026 11:15:37 +0000 Subject: [PATCH 09/12] add pre-commit hook --- .githooks/pre-commit | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..48380a6 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +nix fmt . 2>/dev/null + +changed=$(git diff --name-only) +if [ -n "$changed" ]; then + echo "nix fmt modified files:" + echo "$changed" + echo "" + echo "Stage the changes and retry your commit." + exit 1 +fi From bc9424fc11c18ef998b9c7e3c2c753f60548269b Mon Sep 17 00:00:00 2001 From: will Date: Fri, 20 Mar 2026 09:00:47 +0000 Subject: [PATCH 10/12] fix cmake clang search mismatch --- .github/workflows/depends.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml index c8e5760..f198823 100644 --- a/.github/workflows/depends.yml +++ b/.github/workflows/depends.yml @@ -91,7 +91,20 @@ jobs: cd bitcoin HOST_TRIPLET=\$(./depends/config.guess) export HOST_TRIPLET - make -C depends -j\$(nproc) NO_QT=1 build_CC="$CC" build_CXX="$CXX" +# + # Nix sets CC/CXX to bare names (e.g. 'clang'), relying on PATH. + # The depends Makefile substitutes CC/CXX into toolchain.cmake, + # but cmake's find_program searches system dirs before PATH, + # so a bare 'clang' resolves to /usr/bin/clang (system) instead + # of the Nix clang. This causes glibc version mismatches: Nix + # compiles against glibc 2.42 headers, but the system linker + # links against the runner's older glibc, producing undefined + # references to fortified symbols like __inet_pton_chk. + # Resolve to absolute Nix store paths to avoid this. + NIX_CC=\$(command -v \$CC) + NIX_CXX=\$(command -v \$CXX) + make -C depends -j\$(nproc) NO_QT=1 CC="\$NIX_CC" CXX="\$NIX_CXX" build_CC="\$NIX_CC" build_CXX="\$NIX_CXX" + cmake -B build --toolchain \"depends/\$HOST_TRIPLET/toolchain.cmake\" cmake --build build -j\$(nproc) ccache --show-stats From 88e74ab08b816fd587b9b53e97bd331ae7413e84 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 20 Mar 2026 09:02:36 +0000 Subject: [PATCH 11/12] extract depends build into script --- .github/workflows/depends.yml | 34 +++++----------------------------- scripts/build-depends.sh | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 29 deletions(-) create mode 100755 scripts/build-depends.sh diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml index f198823..5d9a862 100644 --- a/.github/workflows/depends.yml +++ b/.github/workflows/depends.yml @@ -80,32 +80,8 @@ jobs: run: nix flake check - name: Build bitcoin from depends - run: | - nix develop .#depends --command bash -c " - set -eux - - export CCACHE_DIR=${{ env.CCACHE_DIR }} - export SOURCES_PATH=${{ env.SOURCES_PATH }} - export BASE_CACHE=${{ env.BASE_CACHE }} - - cd bitcoin - HOST_TRIPLET=\$(./depends/config.guess) - export HOST_TRIPLET -# - # Nix sets CC/CXX to bare names (e.g. 'clang'), relying on PATH. - # The depends Makefile substitutes CC/CXX into toolchain.cmake, - # but cmake's find_program searches system dirs before PATH, - # so a bare 'clang' resolves to /usr/bin/clang (system) instead - # of the Nix clang. This causes glibc version mismatches: Nix - # compiles against glibc 2.42 headers, but the system linker - # links against the runner's older glibc, producing undefined - # references to fortified symbols like __inet_pton_chk. - # Resolve to absolute Nix store paths to avoid this. - NIX_CC=\$(command -v \$CC) - NIX_CXX=\$(command -v \$CXX) - make -C depends -j\$(nproc) NO_QT=1 CC="\$NIX_CC" CXX="\$NIX_CXX" build_CC="\$NIX_CC" build_CXX="\$NIX_CXX" - - cmake -B build --toolchain \"depends/\$HOST_TRIPLET/toolchain.cmake\" - cmake --build build -j\$(nproc) - ccache --show-stats - " + env: + CCACHE_DIR: ${{ env.CCACHE_DIR }} + SOURCES_PATH: ${{ env.SOURCES_PATH }} + BASE_CACHE: ${{ env.BASE_CACHE }} + run: nix develop .#depends --command ./scripts/build-depends.sh diff --git a/scripts/build-depends.sh b/scripts/build-depends.sh new file mode 100755 index 0000000..bfa8d09 --- /dev/null +++ b/scripts/build-depends.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd bitcoin + +# Nix sets CC/CXX to bare names (e.g. 'clang'), relying on PATH. The depends +# Makefile substitutes these into toolchain.cmake, but cmake's find_program +# searches system dirs before PATH, so a bare 'clang' resolves to the system +# compiler instead of the Nix one. This causes glibc version mismatches: +# objects compiled against Nix's newer glibc headers reference fortified +# symbols (e.g. __inet_pton_chk) absent from the runner's older glibc. +NIX_CC=$(command -v "$CC") +NIX_CXX=$(command -v "$CXX") + +HOST_TRIPLET=$(./depends/config.guess) + +make -C depends "-j$(nproc)" NO_QT=1 \ + CC="$NIX_CC" CXX="$NIX_CXX" \ + build_CC="$NIX_CC" build_CXX="$NIX_CXX" + +cmake -B build --toolchain "depends/$HOST_TRIPLET/toolchain.cmake" +cmake --build build "-j$(nproc)" +ccache --show-stats From 59e175a7484f79caab3506b512ee74c650b2c0d3 Mon Sep 17 00:00:00 2001 From: will Date: Fri, 20 Mar 2026 09:04:54 +0000 Subject: [PATCH 12/12] extract systemlibs build into script --- .github/workflows/nix.yml | 15 +-------------- scripts/build-systemlibs.sh | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 14 deletions(-) create mode 100755 scripts/build-systemlibs.sh diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 1a5d23d..79db485 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -85,17 +85,4 @@ jobs: run: nix flake check - name: Build bitcoind - run: | - nix develop --command bash -c " - set -eux - export CCACHE_DIR=${{ env.CCACHE_DIR }} - cd bitcoin - cmake -B build \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - --preset dev-mode \ - -DBUILD_GUI=OFF \ - ${{ matrix.cmake_flags }} - cmake --build build -j${{ matrix.cores }} - ccache --show-stats - " + run: nix develop --command ./scripts/build-systemlibs.sh ${{ matrix.cores }} ${{ matrix.cmake_flags }} diff --git a/scripts/build-systemlibs.sh b/scripts/build-systemlibs.sh new file mode 100755 index 0000000..d3f51b2 --- /dev/null +++ b/scripts/build-systemlibs.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +CORES=${1:?usage: build-systemlibs.sh [cmake_flags...]} +shift +CMAKE_FLAGS=("$@") + +cd bitcoin +cmake -B build \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + --preset dev-mode \ + -DBUILD_GUI=OFF \ + "${CMAKE_FLAGS[@]}" +cmake --build build "-j$CORES" +ccache --show-stats