diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000..3550a30f2d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/docs/build/environment.md b/docs/build/environment.md index 2cca608567..e639ed2d5f 100644 --- a/docs/build/environment.md +++ b/docs/build/environment.md @@ -33,9 +33,10 @@ with a single command and without installing anything system-wide: nix --experimental-features 'nix-command flakes' develop ``` -On **Linux**, Nix also provides the compiler (GCC). On **macOS**, the shell uses -your **system-wide Apple Clang** as the compiler, so you still need to manage -its version (see below). +On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides +Clang. If you instead opt to use your system-wide Apple Clang (via +`nix develop .#apple-clang`), you need to manage its version yourself (see +below). See [Using the Nix development shell](./nix.md) for installation and usage details, including how to select a different compiler. @@ -48,10 +49,10 @@ details, including how to select a different compiler. ### macOS: managing the Apple Clang version -Because the Nix shell uses the system-wide Apple Clang on macOS, the compiler -version is whatever your installed Xcode (or Command Line Tools) provides. The -following command should return a version greater than or equal to the -[minimum required](#tested-compiler-versions): +If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`), +the compiler version is whatever your installed Xcode (or Command Line Tools) +provides. The following command should return a version greater than or equal to +the [minimum required](#tested-compiler-versions): ```bash clang --version diff --git a/docs/build/nix.md b/docs/build/nix.md index 2ae483aefe..d6e53a254a 100644 --- a/docs/build/nix.md +++ b/docs/build/nix.md @@ -9,7 +9,7 @@ This guide explains how to use Nix to set up a reproducible development environm - **Reproducible environment**: Everyone gets the same versions of tools and compilers - **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment - **No system pollution**: Dependencies are isolated and don't affect your system packages -- **Multiple compiler versions**: Easily switch between different GCC and Clang versions +- **Consistent compilers**: The GCC and Clang shells use the same versions as CI - **Quick setup**: Get started with a single command - **Works on Linux and macOS**: Consistent experience across platforms @@ -31,8 +31,8 @@ This will: - Download and set up all required development tools (CMake, Ninja, Conan, etc.) - Configure the appropriate compiler for your platform: - - **Linux**: GCC 15.2 (provided by Nix) - - **macOS**: Apple Clang (your system compiler) + - **Linux**: GCC (provided by Nix) + - **macOS**: Clang (provided by Nix) The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster. @@ -40,12 +40,12 @@ The first time you run this command, it will take a few minutes to download and - **Linux**: `nix develop` gives you a shell with all the tooling necessary to develop xrpld and with GCC 15.2 (also provided by Nix). There are no caveats. -- **macOS**: `nix develop` gives you a full environment too. The compiler is - your system-wide Apple Clang, while every other tool — including Conan — is - provided by Nix. Conan has no binary in the Nix cache for macOS, so it is - built from source the first time you enter the shell, which makes the initial - setup slower (this is handled automatically; see - [`nix/devshell.nix`](../../nix/devshell.nix)). +- **macOS**: `nix develop` gives you a full environment too, with Clang (and + every other tool, including Conan) provided by Nix. To use your system-wide + Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in + the Nix cache for macOS, so it is built from source the first time you enter + the shell, which makes the initial setup slower (this is handled + automatically; see [`nix/devshell.nix`](../../nix/devshell.nix)). > [!TIP] > To avoid typing `--experimental-features 'nix-command flakes'` every time, you can permanently enable flakes by creating `~/.config/nix/nix.conf`: @@ -62,7 +62,9 @@ The first time you run this command, it will take a few minutes to download and ### Choosing a different compiler -A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#gcc15`. +A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`. +The `.#gcc` and `.#clang` shells provide the same GCC and Clang versions used in CI +(pinned in [`nix/packages.nix`](../../nix/packages.nix)). Use `nix flake show` to see all the available development shells. Use `nix develop .#no-compiler` to use the compiler from your system. @@ -70,11 +72,11 @@ Use `nix develop .#no-compiler` to use the compiler from your system. ### Example Usage ```bash -# Use GCC 14 -nix develop .#gcc14 +# Use GCC (same version as CI) +nix develop .#gcc -# Use Clang 19 -nix develop .#clang19 +# Use Clang (same version as CI) +nix develop .#clang # Use default for your platform nix develop @@ -112,7 +114,15 @@ Once inside the Nix development shell, follow the standard [build instructions]( [direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory. -This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`. To use it, install direnv for your shell, then add an `.envrc` containing `use flake` at the repository root and run `direnv allow`. +This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`. + +The repository already ships an `.envrc` at its root that activates the Nix flake development shell, so you don't need to create one. To use it: + +1. [Install direnv](https://direnv.net/docs/installation.html) and [hook it into your shell](https://direnv.net/docs/hook.html) (bash, zsh, fish, …). Installing [nix-direnv](https://github.com/nix-community/nix-direnv) as well is recommended: it caches the shell so that activation is near-instant after the first run. +2. Run `direnv allow` once in the repository root. direnv will then load (and reload) the Nix development shell automatically whenever you enter the directory. + +> [!NOTE] +> direnv only caches the `.direnv` directory (already listed in `.gitignore`); no other repository files are affected. ## Conan and Prebuilt Packages diff --git a/nix/ci-env.nix b/nix/ci-env.nix index f823f71de0..9b754af97d 100644 --- a/nix/ci-env.nix +++ b/nix/ci-env.nix @@ -4,14 +4,16 @@ ... }: let - inherit (import ./packages.nix { inherit pkgs; }) commonPackages; - inherit (pkgs) lib; + inherit (import ./packages.nix { inherit pkgs; }) + commonPackages + gccPackage + llvmPackages + llvmVersion + ; - # Underlying compiler toolchains to wrap. Bump these in one place to - # roll the whole environment forward. - customGccPackage = pkgs.gcc15; - customLlvmPackages = pkgs.llvmPackages_22; - customClangMajor = lib.versions.major (lib.getVersion customLlvmPackages.clang-unwrapped); + # Underlying compiler toolchains to wrap (versions pinned in packages.nix). + customGccPackage = gccPackage; + customLlvmPackages = llvmPackages; # binutils wrapped to emit binaries that reference the custom glibc # (dynamic linker path, library search path, RPATH). @@ -90,7 +92,7 @@ let extraBuildCommands = '' rsrc="$out/resource-root" mkdir "$rsrc" - ln -s "${customLlvmPackages.clang-unwrapped.lib}/lib/clang/${customClangMajor}/include" "$rsrc/include" + ln -s "${customLlvmPackages.clang-unwrapped.lib}/lib/clang/${toString llvmVersion}/include" "$rsrc/include" ln -s "${customCompilerRt.out}/lib" "$rsrc/lib" ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags diff --git a/nix/devshell.nix b/nix/devshell.nix index 1bd7ea4c0c..34f173ef08 100644 --- a/nix/devshell.nix +++ b/nix/devshell.nix @@ -1,127 +1,57 @@ { pkgs, ... }: let - inherit (import ./packages.nix { inherit pkgs; }) commonPackages; + inherit (import ./packages.nix { inherit pkgs; }) + commonPackages + gccVersion + llvmPackages + ; - # Supported compiler versions - gccVersion = pkgs.lib.range 13 15; - clangVersions = pkgs.lib.range 18 21; + # Plain nixpkgs stdenvs — no custom glibc, unlike ci-env.nix. + gccStdenv = pkgs."gcc${toString gccVersion}Stdenv"; + clangStdenv = llvmPackages.stdenv; - defaultCompiler = if pkgs.stdenv.isDarwin then "apple-clang" else "gcc"; - defaultGccVersion = pkgs.lib.last gccVersion; - defaultClangVersion = pkgs.lib.last clangVersions; - - strToCompilerEnv = - compiler: version: - ( - if compiler == "gcc" then - let - gccPkg = pkgs."gcc${toString version}Stdenv" or null; - in - if gccPkg != null && builtins.elem version gccVersion then - gccPkg - else - throw "Invalid GCC version: ${toString version}. Must be one of: ${toString gccVersion}" - else if compiler == "clang" then - let - clangPkg = pkgs."llvmPackages_${toString version}".stdenv or null; - in - if clangPkg != null && builtins.elem version clangVersions then - clangPkg - else - throw "Invalid Clang version: ${toString version}. Must be one of: ${toString clangVersions}" - else if compiler == "apple-clang" || compiler == "none" then - pkgs.stdenvNoCC - else - throw "Invalid compiler: ${compiler}. Must be one of: gcc, clang, apple-clang, none" - ); - - # Helper function to create a shell with a specific compiler + # compilerName is the command used to print the version, or null for none. makeShell = { - compiler ? defaultCompiler, - version ? ( - if compiler == "gcc" then - defaultGccVersion - else if compiler == "clang" then - defaultClangVersion - else - null - ), + stdenv, + compilerName, }: let - compilerStdEnv = strToCompilerEnv compiler version; - - compilerName = - if compiler == "apple-clang" then - "clang" - else if compiler == "none" then - null - else - compiler; - - gccOnMacWarning = - if pkgs.stdenv.isDarwin && compiler == "gcc" then - '' - echo "WARNING: Using GCC on macOS with Conan may not work." - echo " Consider using 'nix develop .#clang' or the default shell instead." - echo "" - '' - else - ""; - compilerVersion = - if compilerName != null then + if compilerName == null then + ''echo "No compiler specified - using system compiler"'' + else '' echo "Compiler: " ${compilerName} --version - '' - else - '' - echo "No compiler specified - using system compiler" ''; - - shellAttrs = { - packages = commonPackages; - - shellHook = '' - echo "Welcome to xrpld development shell"; - ${gccOnMacWarning}${compilerVersion} - ''; - }; in - pkgs.mkShell.override { stdenv = compilerStdEnv; } shellAttrs; - - # Generate shells for each compiler version - gccShells = builtins.listToAttrs ( - map (version: { - name = "gcc${toString version}"; - value = makeShell { - compiler = "gcc"; - version = version; - }; - }) gccVersion - ); - - clangShells = builtins.listToAttrs ( - map (version: { - name = "clang${toString version}"; - value = makeShell { - compiler = "clang"; - version = version; - }; - }) clangVersions - ); - + (pkgs.mkShell.override { inherit stdenv; }) { + packages = commonPackages; + shellHook = '' + echo "Welcome to xrpld development shell"; + ${compilerVersion} + ''; + }; in -gccShells -// clangShells -// { - # Default shells - default = makeShell { }; - gcc = makeShell { compiler = "gcc"; }; - clang = makeShell { compiler = "clang"; }; +rec { + # macOS: Nix Clang. Linux: Nix GCC. + default = if pkgs.stdenv.isDarwin then clang else gcc; - # No compiler - no-compiler = makeShell { compiler = "none"; }; - apple-clang = makeShell { compiler = "apple-clang"; }; + gcc = makeShell { + stdenv = gccStdenv; + compilerName = "gcc"; + }; + + clang = makeShell { + stdenv = clangStdenv; + compilerName = "clang"; + }; + + # Nix provides no compiler; use the one from your system (e.g. Apple Clang). + no-compiler = makeShell { + stdenv = pkgs.stdenvNoCC; + compilerName = null; + }; + apple-clang = no-compiler; } diff --git a/nix/packages.nix b/nix/packages.nix index bcadfe7456..bf10ee3712 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -1,15 +1,33 @@ { pkgs }: let + # Compiler versions used across the dev shell and the CI environment. + gccVersion = 15; + llvmVersion = 22; + + gccPackage = pkgs."gcc${toString gccVersion}"; + llvmPackages = pkgs."llvmPackages_${toString llvmVersion}"; + + # Bound explicitly so it tracks llvmPackages above, not the `with pkgs` default. + clangTools = llvmPackages.clang-tools; + # In LLVM 22, run-clang-tidy.py moved from share/clang/ to bin/, so nixpkgs # clang-tools no longer links it. Wrap it manually. runClangTidy = pkgs.writeShellScriptBin "run-clang-tidy" '' - exec ${pkgs.python3}/bin/python3 ${pkgs.llvmPackages_22.clang-unwrapped}/bin/run-clang-tidy "$@" + exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@" ''; in { + inherit + gccVersion + llvmVersion + gccPackage + llvmPackages + ; + commonPackages = with pkgs; [ ccache clangbuildanalyzer + clangTools cmake conan curlMinimal # needed for codecov/codecov-action @@ -23,7 +41,6 @@ in gnumake gnupg # needed for signing commits & codecov/codecov-action graphviz - llvmPackages_22.clang-tools less # needed for git diff mold nettools # provides netstat, used to debug failures in CI diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 820936a22d..793ddb18d2 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -23,7 +23,7 @@ namespace { //------------------------------------------------------------------------------ // clang-format off // NOLINTNEXTLINE(readability-identifier-naming) -char const* const versionString = "3.3.0-b0" +char const* const versionString = "3.3.0-b1" // clang-format on ;