From 3122de86bfd3b41c5f14361dedadb4752b32ae96 Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Wed, 22 Jul 2026 17:04:02 +0000 Subject: [PATCH] build: Create versioned compiler/tooling symlinks in nix environments (#7844) --- .cspell.config.yaml | 1 + nix/ci-env.nix | 21 +++++++++++++++++++ nix/devshell.nix | 23 ++++++++++++++++++++- nix/packages.nix | 50 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/.cspell.config.yaml b/.cspell.config.yaml index e26eef9227..c862379f08 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -341,6 +341,7 @@ words: - unsquelch - unsquelched - unsquelching + - unsuffixed - unvalidated - unveto - unvetoed diff --git a/nix/ci-env.nix b/nix/ci-env.nix index 9b754af97d..63bddb46d8 100644 --- a/nix/ci-env.nix +++ b/nix/ci-env.nix @@ -7,8 +7,10 @@ let inherit (import ./packages.nix { inherit pkgs; }) commonPackages gccPackage + gccVersion llvmPackages llvmVersion + mkVersionedToolLinks ; # Underlying compiler toolchains to wrap (versions pinned in packages.nix). @@ -127,6 +129,25 @@ in customGcov customClangForCiEnv customBinutils + (mkVersionedToolLinks { + name = "gcc"; + package = customGcc; + version = gccVersion; + tools = [ + "gcc" + "g++" + "cpp" + ]; + }) + (mkVersionedToolLinks { + name = "clang"; + package = customClang; + version = llvmVersion; + tools = [ + "clang" + "clang++" + ]; + }) # CA certificate bundle so HTTPS clients (git, curl, conan) can verify # TLS connections without ca-certificates being installed in the system. pkgs.cacert diff --git a/nix/devshell.nix b/nix/devshell.nix index 34f173ef08..1316fe4234 100644 --- a/nix/devshell.nix +++ b/nix/devshell.nix @@ -3,7 +3,9 @@ let inherit (import ./packages.nix { inherit pkgs; }) commonPackages gccVersion + llvmVersion llvmPackages + mkVersionedToolLinks ; # Plain nixpkgs stdenvs — no custom glibc, unlike ci-env.nix. @@ -15,6 +17,8 @@ let { stdenv, compilerName, + version ? null, + versionedTools ? [ ], }: let compilerVersion = @@ -25,9 +29,15 @@ let echo "Compiler: " ${compilerName} --version ''; + versionedLinks = pkgs.lib.optional (version != null) (mkVersionedToolLinks { + name = compilerName; + package = stdenv.cc; + inherit version; + tools = versionedTools; + }); in (pkgs.mkShell.override { inherit stdenv; }) { - packages = commonPackages; + packages = commonPackages ++ versionedLinks; shellHook = '' echo "Welcome to xrpld development shell"; ${compilerVersion} @@ -41,11 +51,22 @@ rec { gcc = makeShell { stdenv = gccStdenv; compilerName = "gcc"; + version = gccVersion; + versionedTools = [ + "gcc" + "g++" + "cpp" + ]; }; clang = makeShell { stdenv = clangStdenv; compilerName = "clang"; + version = llvmVersion; + versionedTools = [ + "clang" + "clang++" + ]; }; # Nix provides no compiler; use the one from your system (e.g. Apple Clang). diff --git a/nix/packages.nix b/nix/packages.nix index dbd9597c25..1d9b6cd2f8 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -17,6 +17,53 @@ let ''; rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml; + + # Nix wraps its toolchain so that binaries are exposed only under unsuffixed + # names (gcc, g++, clang-tidy, ...). Several tools probe for a + # version-suffixed name first and fall back to a system binary on the PATH + # when Nix doesn't provide it: + # - Conan's Boost recipe looks up `g++-` before plain `g++`. + # - bin/pre-commit/clang_tidy_check.py looks up `run-clang-tidy-` and + # `clang-apply-replacements-` before the unsuffixed names. + # On a host that also has the matching system binary (e.g. Ubuntu's + # `/usr/bin/g++-15` or `clang-tidy-22`) the probe escapes Nix and mixes a + # system tool into the Nix environment. Generate version-suffixed symlinks + # next to a package's tools so those probes resolve to the Nix ones. + # + # Compiler links must point at whichever compiler is active in a given + # environment (the plain stdenv compiler in the dev shell, the custom-glibc + # wrappers in ci-env.nix), so those callers pass their own `package`; the + # clang tooling is environment-independent and is linked in commonPackages. + mkVersionedToolLinks = + { + name, + package, + version, + tools, + }: + pkgs.linkFarm "${name}-${toString version}-versioned-links" ( + map (tool: { + name = "bin/${tool}-${toString version}"; + path = "${package}/bin/${tool}"; + }) tools + ); + + clangToolLinks = mkVersionedToolLinks { + name = "clang-tools"; + package = clangTools; + version = llvmVersion; + tools = [ + "clang-tidy" + "clang-apply-replacements" + "clang-format" + ]; + }; + runClangTidyLink = mkVersionedToolLinks { + name = "run-clang-tidy"; + package = runClangTidy; + version = llvmVersion; + tools = [ "run-clang-tidy" ]; + }; in { inherit @@ -24,9 +71,12 @@ in llvmVersion gccPackage llvmPackages + mkVersionedToolLinks ; commonPackages = with pkgs; [ + clangToolLinks + runClangTidyLink ccache clangbuildanalyzer clangTools