treewide: remove FHSEnv
To remove the FHSenv, we have to patch rules_python to use
/usr/bin/env to resolve the path to bash instead of hardcoding it.
Additionally, we now bring a Nix-compatible Bazel 8.
Change-Id: Id51e7748eea6dd77185f43a52fe45b5110ba4a2b
Reviewed-on: https://review.monogon.dev/c/monogon/+/4427
Tested-by: Jenkins CI
Reviewed-by: Jan Schär <jan@monogon.tech>
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Reviewed-by: Leopold Schabel <leo@monogon.tech>
diff --git a/third_party/nix/default.nix b/third_party/nix/default.nix
index eab83d7..726119e 100644
--- a/third_party/nix/default.nix
+++ b/third_party/nix/default.nix
@@ -9,6 +9,7 @@
util-linux-minimal = import ./pkgs/util-linux { pkgs = super; };
bazel-unwrapped = import ./pkgs/bazel { pkgs = super; };
perl = import ./pkgs/perl { pkgs = super; };
+ bazel_8 = self.callPackage ./pkgs/bazel_8/package.nix { };
python3Minimal = import ./pkgs/python3 { pkgs = super; };
bison = import ./pkgs/bison { pkgs = super; };
})
diff --git a/third_party/nix/pkgs/bazel/BUILD.bazel b/third_party/nix/pkgs/bazel/BUILD.bazel
deleted file mode 100644
index e69de29..0000000
--- a/third_party/nix/pkgs/bazel/BUILD.bazel
+++ /dev/null
diff --git a/third_party/nix/pkgs/bazel/bazel-inner.sh b/third_party/nix/pkgs/bazel/bazel-inner.sh
deleted file mode 100755
index 7b978bc..0000000
--- a/third_party/nix/pkgs/bazel/bazel-inner.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/bash
-function get_workspace_root() {
- workspace_dir="${PWD}"
- while [[ "${workspace_dir}" != / ]]; do
- if [[ -e "${workspace_dir}/WORKSPACE" || -e "${workspace_dir}/WORKSPACE.bazel" || -e "${workspace_dir}/MODULE.bazel" ]]; then
- readonly workspace_dir
- return
- fi
- workspace_dir="$(dirname "${workspace_dir}")"
- done
- readonly workspace_dir=""
-}
-
-get_workspace_root
-readonly wrapper="${workspace_dir}/tools/bazel"
-if [ -f "${wrapper}" ]; then
- exec -a "$0" "${wrapper}" "$@"
-fi
-exec -a "$0" "${BAZEL_REAL}" "$@"
diff --git a/third_party/nix/pkgs/bazel/default.nix b/third_party/nix/pkgs/bazel/default.nix
deleted file mode 100644
index c181db3..0000000
--- a/third_party/nix/pkgs/bazel/default.nix
+++ /dev/null
@@ -1,24 +0,0 @@
-{ pkgs }: with pkgs;
-stdenv.mkDerivation {
- name = "bazel";
- src = builtins.fetchurl {
- url = "https://github.com/bazelbuild/bazel/releases/download/8.3.1/bazel-8.3.1-linux-x86_64";
- sha256 = "0k3067d06b8160day48afskr42c41bz0qgb3pk9mjpr4hj57w90p";
- };
- unpackPhase = ''
- true
- '';
- nativeBuildInputs = [ makeWrapper ];
- buildPhase = ''
- mkdir -p $out/bin
- cp $src $out/bin/.bazel-inner
- chmod +x $out/bin/.bazel-inner
-
- cp ${./bazel-inner.sh} $out/bin/bazel
- chmod +x $out/bin/bazel
-
- # Use wrapProgram to set the actual bazel path
- wrapProgram $out/bin/bazel --set BAZEL_REAL $out/bin/.bazel-inner
- '';
- dontStrip = true;
-}
diff --git a/third_party/nix/pkgs/bazel_8/LICENSE b/third_party/nix/pkgs/bazel_8/LICENSE
new file mode 100644
index 0000000..6d47368
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/third_party/nix/pkgs/bazel_8/README.md b/third_party/nix/pkgs/bazel_8/README.md
new file mode 100644
index 0000000..000f0b8
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/README.md
@@ -0,0 +1,6 @@
+# Bazel 8 Nix Package
+
+This build is based on https://github.com/NixOS/nixpkgs/pull/400941, the only
+difference being the addition of `bash` to the default shell environment. As
+soon as the PR is merged, we can replace it with a small override to inject
+bash into the dependencies.
\ No newline at end of file
diff --git a/third_party/nix/pkgs/bazel_8/bazel-execlog.sh b/third_party/nix/pkgs/bazel_8/bazel-execlog.sh
new file mode 100644
index 0000000..7a6fd6c
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/bazel-execlog.sh
@@ -0,0 +1,3 @@
+#!@runtimeShell@
+
+exec @binJava@ -jar @out@/share/parser_deploy.jar "$@"
diff --git a/third_party/nix/pkgs/bazel_8/build-support/bazelDerivation.nix b/third_party/nix/pkgs/bazel_8/build-support/bazelDerivation.nix
new file mode 100644
index 0000000..0d6b3ca
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/build-support/bazelDerivation.nix
@@ -0,0 +1,72 @@
+{ stdenv
+, lndir
+, lib
+,
+}:
+
+args@{ bazel
+, registry ? null
+, bazelRepoCache ? null
+, bazelVendorDeps ? null
+, startupArgs ? [ ]
+, commandArgs ? [ ]
+, bazelPreBuild ? ""
+, bazelPostBuild ? ""
+, serverJavabase ? null
+, targets
+, command
+, ...
+}:
+
+stdenv.mkDerivation (
+ {
+ preBuildPhases = [ "preBuildPhase" ];
+ preBuildPhase =
+ (lib.optionalString (bazelRepoCache != null) ''
+ # repo_cache needs to be writeable even in air-gapped builds
+ mkdir repo_cache
+ ${lndir}/bin/lndir -silent ${bazelRepoCache}/repo_cache repo_cache
+ '')
+
+ + (lib.optionalString (bazelVendorDeps != null) ''
+ mkdir vendor_dir
+ ${lndir}/bin/lndir -silent ${bazelVendorDeps}/vendor_dir vendor_dir
+
+ # pin all deps to avoid re-fetch attempts by Bazel
+ rm vendor_dir/VENDOR.bazel
+ find vendor_dir -maxdepth 1 -type d -printf "pin(\"@@%P\")\n" > vendor_dir/VENDOR.bazel
+ '')
+ # keep preBuildPhase always defined as it is listed in preBuildPhases
+ + ''
+ true
+ '';
+ buildPhase = ''
+ runHook preBuild
+
+ export HOME=$(mktemp -d)
+
+ ${bazelPreBuild}
+
+ ${bazel}/bin/bazel ${
+ lib.strings.concatStringsSep " " (
+ lib.optional (serverJavabase != null) "--server_javabase=${serverJavabase}"
+ ++ [ "--batch" ]
+ ++ startupArgs
+ )
+ } ${command} ${
+ lib.strings.concatStringsSep " " (
+ lib.optional (registry != null) "--registry=file://${registry}"
+ ++ lib.optional (bazelRepoCache != null) "--repository_cache=repo_cache"
+ ++ lib.optional (bazelVendorDeps != null) "--vendor_dir=vendor_dir"
+ ++ commandArgs
+ )
+ } ${lib.strings.concatStringsSep " " targets}
+
+ ${bazelPostBuild}
+
+ runHook postBuild
+ '';
+
+ }
+ // args
+)
diff --git a/third_party/nix/pkgs/bazel_8/build-support/bazelPackage.nix b/third_party/nix/pkgs/bazel_8/build-support/bazelPackage.nix
new file mode 100644
index 0000000..ee33b6e
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/build-support/bazelPackage.nix
@@ -0,0 +1,164 @@
+{ callPackage
+, gnugrep
+, lib
+, autoPatchelfHook
+, stdenv
+,
+}:
+
+{ name
+, src
+, sourceRoot ? null
+, version ? null
+, targets
+, bazel
+, startupArgs ? [ ]
+, commandArgs ? [ ]
+, env ? { }
+, serverJavabase ? null
+, registry ? null
+, bazelRepoCacheFOD ? {
+ outputHash = null;
+ outputHashAlgo = "sha256";
+ }
+, bazelVendorDepsFOD ? {
+ outputHash = null;
+ outputHashAlgo = "sha256";
+ }
+, installPhase
+, buildInputs ? [ ]
+, nativeBuildInputs ? [ ]
+, autoPatchelfIgnoreMissingDeps ? null
+,
+}:
+let
+ # FOD produced by `bazel fetch`
+ # Repo cache contains content-addressed external Bazel dependencies without any patching
+ # Potentially this can be nixified via --experimental_repository_resolved_file
+ # (Note: file itself isn't reproducible because it has lots of extra info and order
+ # isn't stable too. Parsing it into nix fetch* commands isn't trivial but might be possible)
+ bazelRepoCache =
+ if bazelRepoCacheFOD.outputHash == null then
+ null
+ else
+ (callPackage ./bazelDerivation.nix { } {
+ name = "bazelRepoCache";
+ inherit (bazelRepoCacheFOD) outputHash outputHashAlgo;
+ inherit
+ src
+ version
+ sourceRoot
+ env
+ buildInputs
+ nativeBuildInputs
+ ;
+ inherit registry;
+ inherit
+ bazel
+ targets
+ startupArgs
+ serverJavabase
+ ;
+ command = "fetch";
+ outputHashMode = "recursive";
+ commandArgs = [ "--repository_cache repo_cache" ] ++ commandArgs;
+ bazelPreBuild = ''
+ mkdir repo_cache
+ '';
+ installPhase = ''
+ mkdir -p $out/repo_cache
+ cp -r --reflink=auto repo_cache/* $out/repo_cache
+ '';
+ });
+ # Stage1: FOD produced by `bazel vendor`, Stage2: eventual patchelf or other tuning
+ # Vendor deps contains unpacked&patches external dependencies, this may need Nix-specific
+ # patching to address things like
+ # - broken symlinks
+ # - symlinks or other references to absolute nix store paths which isn't allowed for FOD
+ # - autoPatchelf for externally-fetched binaries
+ #
+ # Either repo cache or vendor deps should be enough to build a given package
+ bazelVendorDeps =
+ if bazelVendorDepsFOD.outputHash == null then
+ null
+ else
+ (
+ let
+ stage1 = callPackage ./bazelDerivation.nix { } {
+ name = "bazelVendorDepsStage1";
+ inherit (bazelVendorDepsFOD) outputHash outputHashAlgo;
+ inherit
+ src
+ version
+ sourceRoot
+ env
+ buildInputs
+ nativeBuildInputs
+ ;
+ inherit registry;
+ inherit
+ bazel
+ targets
+ startupArgs
+ serverJavabase
+ ;
+ dontFixup = true;
+ command = "vendor";
+ outputHashMode = "recursive";
+ commandArgs = [ "--vendor_dir vendor_dir" ] ++ commandArgs;
+ bazelPreBuild = ''
+ mkdir vendor_dir
+ '';
+ bazelPostBuild = ''
+ # remove symlinks that point to locations under bazel_src/
+ find vendor_dir -type l -lname "$HOME/*" -exec rm '{}' \;
+ # remove symlinks to temp build directory on darwin
+ find vendor_dir -type l -lname "/private/var/tmp/*" -exec rm '{}' \;
+ # remove broken symlinks
+ find vendor_dir -xtype l -exec rm '{}' \;
+
+ # remove .marker files referencing NIX_STORE as those references aren't allowed in FOD
+ (${gnugrep}/bin/grep -rI "$NIX_STORE/" vendor_dir --files-with-matches --include="*.marker" --null || true) \
+ | xargs -0 --no-run-if-empty rm
+ '';
+ installPhase = ''
+ mkdir -p $out/vendor_dir
+ cp -r --reflink=auto vendor_dir/* $out/vendor_dir
+ '';
+
+ };
+ in
+ stdenv.mkDerivation {
+ name = "bazelVendorDeps";
+ buildInputs = lib.optional (!stdenv.hostPlatform.isDarwin) autoPatchelfHook ++ buildInputs;
+ inherit autoPatchelfIgnoreMissingDeps;
+ src = stage1;
+ installPhase = ''
+ cp -r . $out
+ '';
+ }
+ );
+
+ package = callPackage ./bazelDerivation.nix { } {
+ inherit
+ name
+ src
+ version
+ sourceRoot
+ env
+ buildInputs
+ nativeBuildInputs
+ ;
+ inherit registry bazelRepoCache bazelVendorDeps;
+ inherit
+ bazel
+ targets
+ startupArgs
+ serverJavabase
+ commandArgs
+ ;
+ inherit installPhase;
+ command = "build";
+ };
+in
+package // { passthru = { inherit bazelRepoCache bazelVendorDeps; }; }
diff --git a/third_party/nix/pkgs/bazel_8/build-support/patching.nix b/third_party/nix/pkgs/bazel_8/build-support/patching.nix
new file mode 100644
index 0000000..f43065b
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/build-support/patching.nix
@@ -0,0 +1,24 @@
+{ stdenv
+,
+}:
+{
+ # If there's a need to patch external dependencies managed by Bazel
+ # one option is to configure patches on Bazel level. Bazel doesn't
+ # allow patches to be in absolute paths so this helper will produce
+ # sources patch that adds given file to given location
+ addFilePatch =
+ { path
+ , file
+ ,
+ }:
+ stdenv.mkDerivation {
+ name = "add_file.patch";
+ dontUnpack = true;
+ buildPhase = ''
+ mkdir -p $(dirname "${path}")
+ cp ${file} "${path}"
+ diff -u /dev/null "${path}" >result.patch || true # diff exit code is non-zero if there's a diff
+ '';
+ installPhase = ''cp result.patch $out'';
+ };
+}
diff --git a/third_party/nix/pkgs/bazel_8/defaultShell.nix b/third_party/nix/pkgs/bazel_8/defaultShell.nix
new file mode 100644
index 0000000..0deb516
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/defaultShell.nix
@@ -0,0 +1,41 @@
+{ lib
+, makeBinaryWrapper
+, writeShellApplication
+, bash
+, stdenv
+,
+}:
+{ defaultShellUtils }:
+let
+ defaultShellPath = lib.makeBinPath defaultShellUtils;
+
+ bashWithDefaultShellUtilsSh = writeShellApplication {
+ name = "bash";
+ runtimeInputs = defaultShellUtils;
+ # Empty PATH in Nixpkgs Bash is translated to /no-such-path
+ # On other distros empty PATH search fallback is looking in standard
+ # locations like /bin,/usr/bin
+ # For Bazel many rules rely on such search finding some common utils,
+ # so we provide them in case rules or arguments didn't specify a precise PATH
+ text = ''
+ if [[ "$PATH" == "/no-such-path" ]]; then
+ export PATH=${defaultShellPath}
+ fi
+ exec ${bash}/bin/bash "$@"
+ '';
+ };
+
+in
+{
+ inherit defaultShellUtils defaultShellPath;
+ # Script-based interpreters in shebangs aren't guaranteed to work,
+ # especially on MacOS. So let's produce a binary
+ bashWithDefaultShellUtils = stdenv.mkDerivation {
+ name = "bash";
+ src = bashWithDefaultShellUtilsSh;
+ nativeBuildInputs = [ makeBinaryWrapper ];
+ buildPhase = ''
+ makeWrapper ${bashWithDefaultShellUtilsSh}/bin/bash $out/bin/bash
+ '';
+ };
+}
diff --git a/third_party/nix/pkgs/bazel_8/examples.nix b/third_party/nix/pkgs/bazel_8/examples.nix
new file mode 100644
index 0000000..18b3647
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/examples.nix
@@ -0,0 +1,116 @@
+{ fetchFromGitHub
+, lib
+, bazel_8
+, libgcc
+, cctools
+, stdenv
+, jdk_headless
+, callPackage
+, zlib
+,
+}:
+let
+ bazelPackage = callPackage ./build-support/bazelPackage.nix { };
+ registry = fetchFromGitHub {
+ owner = "bazelbuild";
+ repo = "bazel-central-registry";
+ rev = "9342d3ec42ebafc2c06c33aa9d83b25ed984ebb1";
+ sha256 = "sha256-VT63Y8w9BawBXl5xgujG4Gv3SEGbUADGVsNPdUoDvsY=";
+ };
+ src = fetchFromGitHub {
+ owner = "bazelbuild";
+ repo = "examples";
+ rev = "568db753be213cc4be6c599e54ca64061ddbe6da";
+ sha256 = "sha256-F+iKi82uGWmJ+ICpITePdsA1SkncavSdgLkOKMr5LwM=";
+ };
+in
+{
+ java = bazelPackage {
+ inherit src registry;
+ sourceRoot = "source/java-tutorial";
+ name = "java-tutorial";
+ targets = [ "//:ProjectRunner" ];
+ bazel = bazel_8;
+ commandArgs = [
+ "--extra_toolchains=@@rules_java++toolchains+local_jdk//:all"
+ "--tool_java_runtime_version=local_jdk_21"
+ ];
+ env = {
+ JAVA_HOME = jdk_headless.home;
+ USE_BAZEL_VERSION = bazel_8.version;
+ };
+ installPhase = ''
+ mkdir $out
+ cp bazel-bin/ProjectRunner.jar $out/
+ '';
+ nativeBuildInputs = lib.optional (stdenv.hostPlatform.isDarwin) cctools;
+ bazelRepoCacheFOD = {
+ outputHash = lib.attrsets.attrByPath [ stdenv.hostPlatform.system ] null {
+ x86_64-linux = "sha256-64Ze+t0UYR2qQNECWes27SjzdkP+z5eJsCAO+OR+h/o=";
+ x86_64-darwin = lib.fakeHash;
+ aarch64-linux = "sha256-vEcOTdJM2YYle3PijKwroyM7LpfyK/3k/egRKDbjsmU=";
+ aarch64-darwin = "sha256-ya85EJikYXWpjtlgNu7i0DqtACgZBsppGEv3SVoJ6JA=";
+ };
+ outputHashAlgo = "sha256";
+ };
+ };
+ cpp = bazelPackage {
+ inherit src registry;
+ sourceRoot = "source/cpp-tutorial/stage3";
+ name = "cpp-tutorial";
+ targets = [ "//main:hello-world" ];
+ bazel = bazel_8;
+ installPhase = ''
+ mkdir $out
+ cp bazel-bin/main/hello-world $out/
+ '';
+ nativeBuildInputs = lib.optional (stdenv.hostPlatform.isDarwin) cctools;
+ commandArgs = lib.optionals (stdenv.hostPlatform.isDarwin) [
+ "--host_cxxopt=-xc++"
+ "--cxxopt=-xc++"
+ ];
+ env = {
+ USE_BAZEL_VERSION = bazel_8.version;
+ };
+ bazelRepoCacheFOD = {
+ outputHash =
+ {
+ x86_64-linux = "sha256-oPPWQdflAPMxF9YPazC//r0R3Sh6fUmNQe0oLM5EBUI=";
+ aarch64-linux = "sha256-oPPWQdflAPMxF9YPazC//r0R3Sh6fUmNQe0oLM5EBUI=";
+ aarch64-darwin = "sha256-oPPWQdflAPMxF9YPazC//r0R3Sh6fUmNQe0oLM5EBUI=";
+ x86_64-darwin = lib.fakeHash;
+ }.${stdenv.hostPlatform.system};
+ outputHashAlgo = "sha256";
+ };
+ };
+ rust = bazelPackage {
+ inherit src registry;
+ sourceRoot = "source/rust-examples/01-hello-world";
+ name = "rust-examples-01-hello-world";
+ targets = [ "//:bin" ];
+ bazel = bazel_8;
+ env = {
+ USE_BAZEL_VERSION = bazel_8.version;
+ };
+ installPhase = ''
+ mkdir $out
+ cp bazel-bin/bin $out/hello-world
+ '';
+ buildInputs = [
+ zlib
+ libgcc
+ ];
+ nativeBuildInputs = lib.optional (stdenv.hostPlatform.isDarwin) cctools;
+ autoPatchelfIgnoreMissingDeps = [ "librustc_driver-*.so" ];
+ bazelVendorDepsFOD = {
+ outputHash =
+ {
+ aarch64-linux = "sha256-2xopm/OCg9A1LqoW1ZesQc5pF/vX0ToIj1JYMtweVR0=";
+ x86_64-linux = "sha256-v987hMC6w2Lwr/PZn2zGHhHmXzecI2koLjOmGz0Mzng=";
+ aarch64-darwin = "sha256-sS7PzLI44dX7P0PY/68YjRSDkNJ6w5BklJNsXPHuOPc=";
+ x86_64-darwin = lib.fakeHash;
+ }.${stdenv.hostPlatform.system};
+ outputHashAlgo = "sha256";
+ };
+ };
+}
diff --git a/third_party/nix/pkgs/bazel_8/package.nix b/third_party/nix/pkgs/bazel_8/package.nix
new file mode 100644
index 0000000..7a27697
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/package.nix
@@ -0,0 +1,355 @@
+{ stdenv
+, callPackage
+, # nix tooling and utilities
+ darwin
+, lib
+, fetchzip
+, fetchpatch
+, makeWrapper
+, writeTextFile
+, replaceVars
+, # native build inputs
+ runtimeShell
+, zip
+, unzip
+, bash
+, coreutils
+, which
+, gawk
+, gnused
+, gnutar
+, gnugrep
+, gzip
+, findutils
+, diffutils
+, gnupatch
+, file
+, installShellFiles
+, python3
+, # Apple dependencies
+ cctools
+, # Allow to independently override the jdks used to build and run respectively
+ jdk_headless
+, # Toggle for hacks for running bazel under buildBazelPackage:
+ # Always assume all markers valid (this is needed because we remove markers; they are non-deterministic).
+ # Also, don't clean up environment variables (so that NIX_ environment variables are passed to compilers).
+ version ? "8.3.1"
+,
+}:
+
+let
+ inherit (callPackage ./build-support/patching.nix { }) addFilePatch;
+ inherit (stdenv.hostPlatform) isDarwin isAarch64;
+
+ bazelSystem = if isDarwin then "darwin" else "linux";
+
+ # on aarch64 Darwin, `uname -m` returns "arm64"
+ bazelArch = if isDarwin && isAarch64 then "arm64" else stdenv.hostPlatform.parsed.cpu.name;
+
+ src = fetchzip {
+ url = "https://github.com/bazelbuild/bazel/releases/download/${version}/bazel-${version}-dist.zip";
+ hash = "sha256-Hiny31S+YF7JdKjxzCyKdw3J/3OdDwsKeOkppfvWrNI=";
+ stripRoot = false;
+ };
+
+ defaultShellUtils =
+ # Keep this list conservative. For more exotic tools, prefer to use
+ # @rules_nixpkgs to pull in tools from the nix repository. Example:
+ #
+ # WORKSPACE:
+ #
+ # nixpkgs_git_repository(
+ # name = "nixpkgs",
+ # revision = "def5124ec8367efdba95a99523dd06d918cb0ae8",
+ # )
+ #
+ # # This defines an external Bazel workspace.
+ # nixpkgs_package(
+ # name = "bison",
+ # repositories = { "nixpkgs": "@nixpkgs//:default.nix" },
+ # )
+ #
+ # some/BUILD.bazel:
+ #
+ # genrule(
+ # ...
+ # cmd = "$(location @bison//:bin/bison) -other -args",
+ # tools = [
+ # ...
+ # "@bison//:bin/bison",
+ # ],
+ # )
+ [
+ coreutils
+ diffutils
+ file
+ findutils
+ gawk
+ gnugrep
+ gnupatch
+ gnused
+ gnutar
+ gzip
+ unzip
+ which
+ zip
+ bash
+ ];
+ defaultShell = callPackage ./defaultShell.nix { } { inherit defaultShellUtils; };
+
+ commandArgs =
+ [
+ "--nobuild_python_zip"
+ "--features=-module_maps"
+ "--host_features=-module_maps"
+ "--announce_rc"
+ "--verbose_failures"
+ "--curses=no"
+ ]
+ ++ lib.optionals (isDarwin) [
+ "--macos_sdk_version=${stdenv.hostPlatform.darwinMinVersion}"
+ "--cxxopt=-isystem"
+ "--cxxopt=${lib.getDev stdenv.cc.libcxx}/include/c++/v1"
+ "--host_cxxopt=-isystem"
+ "--host_cxxopt=${lib.getDev stdenv.cc.libcxx}/include/c++/v1"
+ "--copt=-isystem"
+ "--copt=${lib.getDev darwin.libresolv}/include"
+ "--host_copt=-isystem"
+ "--host_copt=${lib.getDev darwin.libresolv}/include"
+ ];
+
+in
+stdenv.mkDerivation rec {
+ pname = "bazel";
+ inherit version src;
+
+ darwinPatches = [
+ # Bazel integrates with apple IOKit to inhibit and track system sleep.
+ # Inside the darwin sandbox, these API calls are blocked, and bazel
+ # crashes. It seems possible to allow these APIs inside the sandbox, but it
+ # feels simpler to patch bazel not to use it at all. So our bazel is
+ # incapable of preventing system sleep, which is a small price to pay to
+ # guarantee that it will always run in any nix context.
+ #
+ # See also ./bazel_darwin_sandbox.patch in bazel_5. That patch uses
+ # NIX_BUILD_TOP env var to conditionnally disable sleep features inside the
+ # sandbox.
+ #
+ # If you want to investigate the sandbox profile path,
+ # IORegisterForSystemPower can be allowed with
+ #
+ # propagatedSandboxProfile = ''
+ # (allow iokit-open (iokit-user-client-class "RootDomainUserClient"))
+ # '';
+ #
+ # I do not know yet how to allow IOPMAssertion{CreateWithName,Release}
+ ./patches/darwin_sleep.patch
+
+ # Fix DARWIN_XCODE_LOCATOR_COMPILE_COMMAND by removing multi-arch support.
+ # Nixpkgs toolcahins do not support that (yet?) and get confused.
+ # Also add an explicit /usr/bin prefix that will be patched below.
+ (replaceVars ./patches/xcode.patch {
+ usrBinEnv = "${coreutils}/bin/env";
+ clangDarwin = "${stdenv.cc}/bin/clang";
+ codesign = "${darwin.sigtool}/bin/codesign";
+ })
+
+ # Revert preference for apple_support over rules_cc toolchain for now
+ # will need to figure out how to build with apple_support toolchain later
+ ./patches/apple_cc_toolchain.patch
+
+ # On Darwin, the last argument to gcc is coming up as an empty string. i.e: ''
+ # This is breaking the build of any C target. This patch removes the last
+ # argument if it's found to be an empty string.
+ ./patches/trim-last-argument-to-gcc-if-empty.patch
+
+ # fdopen() compilation fix
+ (fetchpatch {
+ url = "https://github.com/madler/zlib/commit/4bd9a71f3539b5ce47f0c67ab5e01f3196dc8ef9.patch";
+ hash = "sha256-wlZY0/XqND5Fk+SJkUCUj7XhGVwUJw/VqVGAlDdqOhs=";
+ stripLen = 1;
+ extraPrefix = "third_party/zlib/";
+ })
+ ];
+
+ patches = lib.optionals isDarwin darwinPatches ++ [
+ # patch that propagates rules_* patches below
+ # patches need to be within source root and can't be absolute paths in Nix store
+ # so rules_* patches are injected via addFilePatch
+ ./patches/deps_patches.patch
+ (addFilePatch {
+ path = "b/third_party/rules_python.patch";
+ file = replaceVars ./patches/rules_python.patch {
+ usrBinEnv = "${coreutils}/bin/env";
+ };
+ })
+ (addFilePatch {
+ path = "b/third_party/rules_java.patch";
+ file = replaceVars ./patches/rules_java.patch {
+ defaultBash = "${defaultShell.bashWithDefaultShellUtils}/bin/bash";
+ };
+ })
+ # Suggested for upstream in https://github.com/bazelbuild/bazel/pull/25936
+ ./patches/build_execlog_parser.patch
+ # Part of suggestion for upstream in https://github.com/bazelbuild/bazel/pull/25934
+ ./patches/env_bash.patch
+ # Suggested for upstream in https://github.com/bazelbuild/bazel/pull/25935
+ ./patches/gen_completion.patch
+
+ # --experimental_strict_action_env (which may one day become the default
+ # see bazelbuild/bazel#2574) hardcodes the default
+ # action environment to a non hermetic value (e.g. "/usr/local/bin").
+ # This is non hermetic on non-nixos systems. On NixOS, bazel cannot find the required binaries.
+ # So we are replacing this bazel paths by defaultShellPath,
+ # improving hermeticity and making it work in nixos.
+ (replaceVars ./patches/strict_action_env.patch {
+ strictActionEnvPatch = defaultShell.defaultShellPath;
+ })
+
+ (replaceVars ./patches/default_bash.patch {
+ defaultBash = "${defaultShell.bashWithDefaultShellUtils}/bin/bash";
+ })
+
+ (replaceVars ./patches/md5sum.patch {
+ md5sum = "${coreutils}/bin/md5sum";
+ })
+
+ # Nix build sandbox can configure custom PATH but doesn't have
+ # /usr/bin/env which is unfortunate https://github.com/NixOS/nixpkgs/issues/6227
+ # and we need to do a silly patch
+ (replaceVars ./patches/usr_bin_env.patch {
+ usrBinEnv = "${coreutils}/bin/env";
+ })
+
+ # Provide default JRE for Bazel process by setting --server_javabase=
+ # in a new default system bazelrc file
+ (replaceVars ./patches/bazel_rc.patch {
+ bazelSystemBazelRCPath = replaceVars ./system.bazelrc {
+ serverJavabase = jdk_headless;
+ };
+ })
+ ];
+
+ meta = with lib; {
+ homepage = "https://github.com/bazelbuild/bazel/";
+ description = "Build tool that builds code quickly and reliably";
+ sourceProvenance = with sourceTypes; [
+ fromSource
+ binaryBytecode # source bundles dependencies as jars
+ ];
+ license = licenses.asl20;
+ teams = [ lib.teams.bazel ];
+ mainProgram = "bazel";
+ platforms = lib.platforms.linux ++ lib.platforms.darwin;
+ };
+
+ nativeBuildInputs =
+ [
+ makeWrapper
+ jdk_headless
+ python3
+ unzip
+ which
+
+ # Shell completion
+ installShellFiles
+ python3.pkgs.absl-py # Needed to build fish completion
+ ]
+ # Needed for execlog
+ ++ lib.optional (!stdenv.hostPlatform.isDarwin) stdenv.cc
+ ++ lib.optional (stdenv.hostPlatform.isDarwin) cctools;
+
+ buildPhase = ''
+ runHook preBuild
+ export HOME=$(mktemp -d)
+
+ # If EMBED_LABEL isn't set, it'd be auto-detected from CHANGELOG.md
+ # and `git rev-parse --short HEAD` which would result in
+ # "3.7.0- (@non-git)" due to non-git build and incomplete changelog.
+ # Actual bazel releases use scripts/release/common.sh which is based
+ # on branch/tag information which we don't have with tarball releases.
+ # Note that .bazelversion is always correct and is based on bazel-*
+ # executable name, version checks should work fine
+ export EMBED_LABEL="${version}"
+
+ echo "Stage 1 - Running bazel bootstrap script"
+ export EXTRA_BAZEL_ARGS="${lib.strings.concatStringsSep " " commandArgs}"
+
+ ${bash}/bin/bash ./compile.sh
+
+ # XXX: get rid of this, or move it to another stage.
+ # It is plain annoying when builds fail.
+ echo "Stage 2 - Generate bazel completions"
+ ${bash}/bin/bash ./scripts/generate_bash_completion.sh \
+ --bazel=./output/bazel \
+ --output=./output/bazel-complete.bash \
+ --prepend=./scripts/bazel-complete-header.bash \
+ --prepend=./scripts/bazel-complete-template.bash
+ ${python3}/bin/python3 ./scripts/generate_fish_completion.py \
+ --bazel=./output/bazel \
+ --output=./output/bazel-complete.fish
+
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ # Bazel binary contains zip archive, which contains text files and a jar
+ # both of which can have store references that might be obscured to Nix
+ # builder in packaged form, so we unpack and extract those references
+
+ # Note: grep isn't necessarily 100% accurate, other approaches could be
+ # to disassemble Jar (slow) or hardcode known references
+ mkdir -p $out/nix-support
+ INSTALL_BASE=$(./output/bazel --batch info install_base)
+ find "$INSTALL_BASE" -type f -exec \
+ ${gnugrep}/bin/grep --text --only-matching --no-filename "$NIX_STORE/[^/]*" '{}' \; \
+ | sort -u >> $out/nix-support/depends
+
+ mkdir -p $out/bin
+
+ # official wrapper scripts that searches for $WORKSPACE_ROOT/tools/bazel if
+ # it can’t find something in tools, it calls
+ # $out/bin/bazel-{version}-{os_arch} The binary _must_ exist with this
+ # naming if your project contains a .bazelversion file.
+ cp ./scripts/packages/bazel.sh $out/bin/bazel
+ versioned_bazel="$out/bin/bazel-${version}-${bazelSystem}-${bazelArch}"
+ mv ./output/bazel "$versioned_bazel"
+ wrapProgram "$versioned_bazel" --suffix PATH : ${defaultShell.defaultShellPath}
+
+ mkdir $out/share
+ cp ./output/parser_deploy.jar $out/share/parser_deploy.jar
+ substitute ${./bazel-execlog.sh} $out/bin/bazel-execlog \
+ --subst-var out \
+ --subst-var-by runtimeShell ${runtimeShell} \
+ --subst-var-by javaBin ${jdk_headless}/bin/java
+ chmod +x $out/bin/bazel-execlog
+
+ # shell completion files
+ installShellCompletion --bash \
+ --name bazel.bash \
+ ./output/bazel-complete.bash
+ installShellCompletion --zsh \
+ --name _bazel \
+ ./scripts/zsh_completion/_bazel
+ installShellCompletion --fish \
+ --name bazel.fish \
+ ./output/bazel-complete.fish
+ '';
+
+ postFixup =
+ # verify that bazel binary still works post-fixup
+ ''
+ USE_BAZEL_VERSION=${version} $out/bin/bazel --batch info release
+ '';
+
+ # Bazel binary includes zip archive at the end that `strip` would end up discarding
+ stripExclude = [ "bin/.bazel-${version}-*-wrapped" ];
+
+ passthru = {
+ tests = {
+ inherit (callPackage ./examples.nix { }) cpp java rust;
+ };
+ };
+}
diff --git a/third_party/nix/pkgs/bazel_8/patches/apple_cc_toolchain.patch b/third_party/nix/pkgs/bazel_8/patches/apple_cc_toolchain.patch
new file mode 100644
index 0000000..32d5b5b
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/apple_cc_toolchain.patch
@@ -0,0 +1,19 @@
+diff --git a/MODULE.bazel b/MODULE.bazel
+index 11a6075175..f53f0c732b 100644
+--- a/MODULE.bazel
++++ b/MODULE.bazel
+@@ -35,10 +35,10 @@ bazel_dep(name = "with_cfg.bzl", version = "0.6.0")
+ bazel_dep(name = "abseil-cpp", version = "20240722.0.bcr.2")
+ bazel_dep(name = "rules_shell", version = "0.2.0")
+
+-# Depend on apple_support first and then rules_cc so that the Xcode toolchain
+-# from apple_support wins over the generic Unix toolchain from rules_cc.
+-bazel_dep(name = "apple_support", version = "1.18.1")
++# Not Depend on apple_support first and then rules_cc so that the Xcode toolchain
++# from apple_support not wins over the generic Unix toolchain from rules_cc.
+ bazel_dep(name = "rules_cc", version = "0.0.17")
++bazel_dep(name = "apple_support", version = "1.18.1")
+
+ # repo_name needs to be used, until WORKSPACE mode is to be supported in bazel_tools
+ bazel_dep(name = "protobuf", version = "29.0", repo_name = "com_google_protobuf")
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/bazel_rc.patch b/third_party/nix/pkgs/bazel_8/patches/bazel_rc.patch
new file mode 100644
index 0000000..a599ac3
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/bazel_rc.patch
@@ -0,0 +1,13 @@
+diff --git a/src/main/cpp/option_processor.cc b/src/main/cpp/option_processor.cc
+index 8f8f15685f..a7ae52d1e4 100644
+--- a/src/main/cpp/option_processor.cc
++++ b/src/main/cpp/option_processor.cc
+@@ -56,7 +56,7 @@ OptionProcessor::OptionProcessor(
+ : workspace_layout_(workspace_layout),
+ startup_options_(std::move(default_startup_options)),
+ parse_options_called_(false),
+- system_bazelrc_path_(BAZEL_SYSTEM_BAZELRC_PATH) {}
++ system_bazelrc_path_("@bazelSystemBazelRCPath@") {}
+
+ OptionProcessor::OptionProcessor(
+ const WorkspaceLayout* workspace_layout,
diff --git a/third_party/nix/pkgs/bazel_8/patches/build_execlog_parser.patch b/third_party/nix/pkgs/bazel_8/patches/build_execlog_parser.patch
new file mode 100644
index 0000000..552bc3b
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/build_execlog_parser.patch
@@ -0,0 +1,28 @@
+diff --git a/compile.sh b/compile.sh
+index 4712355d48..feec286704 100755
+--- a/compile.sh
++++ b/compile.sh
+@@ -76,6 +76,13 @@ bazel_build "src:bazel_nojdk${EXE_EXT}" \
+ --host_platform=@platforms//host \
+ --platforms=@platforms//host \
+ || fail "Could not build Bazel"
++
++bazel_build src/tools/execlog:parser_deploy.jar \
++ --action_env=PATH \
++ --host_platform=@platforms//host \
++ --platforms=@platforms//host \
++ || fail "Could not build parser_deploy.jar"
++
+ bazel_bin_path="$(get_bazel_bin_path)/src/bazel_nojdk${EXE_EXT}"
+ [ -e "$bazel_bin_path" ] \
+ || fail "Could not find freshly built Bazel binary at '$bazel_bin_path'"
+@@ -84,5 +91,8 @@ cp -f "$bazel_bin_path" "output/bazel${EXE_EXT}" \
+ chmod 0755 "output/bazel${EXE_EXT}"
+ BAZEL="$(pwd)/output/bazel${EXE_EXT}"
+
++cp "$(get_bazel_bin_path)/src/tools/execlog/parser_deploy.jar" output/ \
++ || fail "Could not copy 'parser_deploy.jar' to 'output/"
++
+ clear_log
+ display "Build successful! Binary is here: ${BAZEL}"
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/darwin_sleep.patch b/third_party/nix/pkgs/bazel_8/patches/darwin_sleep.patch
new file mode 100644
index 0000000..731ede8
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/darwin_sleep.patch
@@ -0,0 +1,56 @@
+diff --git a/src/main/native/darwin/sleep_prevention_jni.cc b/src/main/native/darwin/sleep_prevention_jni.cc
+index 67c35b201e..e50a58320e 100644
+--- a/src/main/native/darwin/sleep_prevention_jni.cc
++++ b/src/main/native/darwin/sleep_prevention_jni.cc
+@@ -33,31 +33,13 @@ static int g_sleep_state_stack = 0;
+ static IOPMAssertionID g_sleep_state_assertion = kIOPMNullAssertionID;
+
+ int portable_push_disable_sleep() {
+- std::lock_guard<std::mutex> lock(g_sleep_state_mutex);
+- BAZEL_CHECK_GE(g_sleep_state_stack, 0);
+- if (g_sleep_state_stack == 0) {
+- BAZEL_CHECK_EQ(g_sleep_state_assertion, kIOPMNullAssertionID);
+- CFStringRef reasonForActivity = CFSTR("build.bazel");
+- IOReturn success = IOPMAssertionCreateWithName(
+- kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, reasonForActivity,
+- &g_sleep_state_assertion);
+- BAZEL_CHECK_EQ(success, kIOReturnSuccess);
+- }
+- g_sleep_state_stack += 1;
+- return 0;
++ // Unreliable, disable for now
++ return -1;
+ }
+
+ int portable_pop_disable_sleep() {
+- std::lock_guard<std::mutex> lock(g_sleep_state_mutex);
+- BAZEL_CHECK_GT(g_sleep_state_stack, 0);
+- g_sleep_state_stack -= 1;
+- if (g_sleep_state_stack == 0) {
+- BAZEL_CHECK_NE(g_sleep_state_assertion, kIOPMNullAssertionID);
+- IOReturn success = IOPMAssertionRelease(g_sleep_state_assertion);
+- BAZEL_CHECK_EQ(success, kIOReturnSuccess);
+- g_sleep_state_assertion = kIOPMNullAssertionID;
+- }
+- return 0;
++ // Unreliable, disable for now
++ return -1;
+ }
+
+ } // namespace blaze_jni
+diff --git a/src/main/native/darwin/system_suspension_monitor_jni.cc b/src/main/native/darwin/system_suspension_monitor_jni.cc
+index 3483aa7935..51782986ec 100644
+--- a/src/main/native/darwin/system_suspension_monitor_jni.cc
++++ b/src/main/native/darwin/system_suspension_monitor_jni.cc
+@@ -83,10 +83,7 @@ void portable_start_suspend_monitoring() {
+ // Register to receive system sleep notifications.
+ // Testing needs to be done manually. Use the logging to verify
+ // that sleeps are being caught here.
+- suspend_state.connect_port = IORegisterForSystemPower(
+- &suspend_state, ¬ifyPortRef, SleepCallBack, ¬ifierObject);
+- BAZEL_CHECK_NE(suspend_state.connect_port, MACH_PORT_NULL);
+- IONotificationPortSetDispatchQueue(notifyPortRef, queue);
++ // XXX: Unreliable, disable for now
+
+ // Register to deal with SIGCONT.
+ // We register for SIGCONT because we can't catch SIGSTOP.
diff --git a/third_party/nix/pkgs/bazel_8/patches/default_bash.patch b/third_party/nix/pkgs/bazel_8/patches/default_bash.patch
new file mode 100644
index 0000000..a43a9f0
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/default_bash.patch
@@ -0,0 +1,22 @@
+diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+index a982b782e1..d49b047074 100644
+--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
++++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+@@ -89,13 +89,13 @@ public class BazelRuleClassProvider {
+ public boolean useStrictActionEnv;
+ }
+
+- private static final PathFragment FALLBACK_SHELL = PathFragment.create("/bin/bash");
++ private static final PathFragment FALLBACK_SHELL = PathFragment.create("@defaultBash@");
+
+ public static final ImmutableMap<OS, PathFragment> SHELL_EXECUTABLE =
+ ImmutableMap.<OS, PathFragment>builder()
+ .put(OS.WINDOWS, PathFragment.create("c:/msys64/usr/bin/bash.exe"))
+- .put(OS.FREEBSD, PathFragment.create("/usr/local/bin/bash"))
+- .put(OS.OPENBSD, PathFragment.create("/usr/local/bin/bash"))
++ .put(OS.FREEBSD, PathFragment.create("@defaultBash@"))
++ .put(OS.OPENBSD, PathFragment.create("@defaultBash@"))
+ .put(OS.UNKNOWN, FALLBACK_SHELL)
+ .buildOrThrow();
+
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/deps_patches.patch b/third_party/nix/pkgs/bazel_8/patches/deps_patches.patch
new file mode 100644
index 0000000..bf0aad9
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/deps_patches.patch
@@ -0,0 +1,24 @@
+diff --git a/MODULE.bazel b/MODULE.bazel
+--- MODULE.bazel
++++ MODULE.bazel
+@@ -24,12 +24,20 @@
+ bazel_dep(name = "zstd-jni", version = "1.5.6-9")
+ bazel_dep(name = "blake3", version = "1.5.1.bcr.1")
+ bazel_dep(name = "zlib", version = "1.3.1.bcr.5")
+ bazel_dep(name = "rules_java", version = "8.12.0")
++single_version_override(
++ module_name = "rules_java",
++ patches = ["//third_party:rules_java.patch"],
++)
+ bazel_dep(name = "rules_graalvm", version = "0.11.1")
+ bazel_dep(name = "rules_proto", version = "7.0.2")
+ bazel_dep(name = "rules_jvm_external", version = "6.0")
+ bazel_dep(name = "rules_python", version = "0.40.0")
++single_version_override(
++ module_name = "rules_python",
++ patches = ["//third_party:rules_python.patch"],
++)
+ bazel_dep(name = "rules_testing", version = "0.6.0")
+ bazel_dep(name = "googletest", version = "1.15.2", repo_name = "com_google_googletest")
+ bazel_dep(name = "with_cfg.bzl", version = "0.6.0")
+ bazel_dep(name = "abseil-cpp", version = "20240722.0.bcr.2")
diff --git a/third_party/nix/pkgs/bazel_8/patches/env_bash.patch b/third_party/nix/pkgs/bazel_8/patches/env_bash.patch
new file mode 100644
index 0000000..cc20d10
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/env_bash.patch
@@ -0,0 +1,22 @@
+diff --git a/src/zip_files.sh b/src/zip_files.sh
+index 1422a6c659..920c1019d2 100755
+--- a/src/zip_files.sh
++++ b/src/zip_files.sh
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!/usr/bin/env bash
+
+ # Copyright 2019 The Bazel Authors. All rights reserved.
+ #
+
+diff --git a/src/package-bazel.sh b/src/package-bazel.sh
+index 56e94db400..2c614af6c2 100755
+--- a/src/package-bazel.sh
++++ b/src/package-bazel.sh
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!/usr/bin/env bash
+ #
+ # Copyright 2015 The Bazel Authors. All rights reserved.
+ #
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/gen_completion.patch b/third_party/nix/pkgs/bazel_8/patches/gen_completion.patch
new file mode 100644
index 0000000..c3af229
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/gen_completion.patch
@@ -0,0 +1,26 @@
+diff --git a/scripts/generate_bash_completion.sh b/scripts/generate_bash_completion.sh
+index 778810570c..84d2d49a0d 100755
+--- a/scripts/generate_bash_completion.sh
++++ b/scripts/generate_bash_completion.sh
+@@ -68,7 +68,7 @@ mkdir "${tempdir}/root"
+
+ server_javabase_flag=
+ [ -z "${javabase}" ] || server_javabase_flag="--server_javabase=${javabase}"
+-"${bazel}" --output_user_root="${tempdir}/root" ${server_javabase_flag} \
++"${bazel}" --batch --output_user_root="${tempdir}/root" ${server_javabase_flag} \
+ help completion >>"${tempdir}/output"
+
+ [ -z "${append}" ] || cat ${append} >>"${tempdir}/output"
+diff --git a/scripts/generate_fish_completion.py b/scripts/generate_fish_completion.py
+index bafe28979f..a941d8f7f9 100644
+--- a/scripts/generate_fish_completion.py
++++ b/scripts/generate_fish_completion.py
+@@ -102,7 +102,7 @@ class BazelCompletionWriter(object):
+
+ def _get_bazel_output(self, args):
+ return subprocess.check_output(
+- (self._bazel, '--output_user_root={}'.format(self._output_user_root)) +
++ (self._bazel, '--batch', '--output_user_root={}'.format(self._output_user_root)) +
+ tuple(args),
+ universal_newlines=True)
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/md5sum.patch b/third_party/nix/pkgs/bazel_8/patches/md5sum.patch
new file mode 100644
index 0000000..fc49581
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/md5sum.patch
@@ -0,0 +1,22 @@
+diff --git a/src/BUILD b/src/BUILD
+index f61b90738a..2c3a54d36c 100644
+--- a/src/BUILD
++++ b/src/BUILD
+@@ -38,12 +38,12 @@ md5_cmd = "set -e -o pipefail && %s $(SRCS) | %s | %s > $@"
+ }) + embedded_tools_target,
+ outs = ["install_base_key" + suffix],
+ cmd = select({
+- "//src/conditions:darwin": md5_cmd % ("/sbin/md5", "/sbin/md5", "head -c 32"),
+- "//src/conditions:freebsd": md5_cmd % ("/sbin/md5", "/sbin/md5", "head -c 32"),
++ "//src/conditions:darwin": md5_cmd % ("@md5sum@", "@md5sum@", "head -c 32"),
++ "//src/conditions:freebsd": md5_cmd % ("@md5sum@", "@md5sum@", "head -c 32"),
+ # We avoid using the `head` tool's `-c` option, since it does not exist
+ # on OpenBSD.
+- "//src/conditions:openbsd": md5_cmd % ("/bin/md5", "/bin/md5", "dd bs=32 count=1"),
+- "//conditions:default": md5_cmd % ("md5sum", "md5sum", "head -c 32"),
++ "//src/conditions:openbsd": md5_cmd % ("@md5sum@", "@md5sum@", "dd bs=32 count=1"),
++ "//conditions:default": md5_cmd % ("@md5sum@", "@md5sum@", "head -c 32"),
+ }),
+ ) for suffix, embedded_tools_target in {
+ "_jdk_allmodules": [":embedded_tools_jdk_allmodules"],
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/rules_java.patch b/third_party/nix/pkgs/bazel_8/patches/rules_java.patch
new file mode 100644
index 0000000..ba2fd2f
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/rules_java.patch
@@ -0,0 +1,11 @@
+diff --git java/bazel/rules/java_stub_template.txt java/bazel/rules/java_stub_template.txt
+index 115b46e..56d2ff7 100644
+--- java/bazel/rules/java_stub_template.txt
++++ java/bazel/rules/java_stub_template.txt
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env bash
++#!@defaultBash@
+ # Copyright 2014 The Bazel Authors. All rights reserved.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/rules_python.patch b/third_party/nix/pkgs/bazel_8/patches/rules_python.patch
new file mode 100644
index 0000000..a63f44e
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/rules_python.patch
@@ -0,0 +1,14 @@
+diff --git python/private/runtime_env_toolchain.bzl python/private/runtime_env_toolchain.bzl
+--- python/private/runtime_env_toolchain.bzl
++++ python/private/runtime_env_toolchain.bzl
+@@ -42,7 +42,7 @@
+ name = "_runtime_env_py3_runtime",
+ interpreter = "//python/private:runtime_env_toolchain_interpreter.sh",
+ python_version = "PY3",
+- stub_shebang = "#!/usr/bin/env python3",
++ stub_shebang = "#!@usrBinEnv@ python3",
+ visibility = ["//visibility:private"],
+ tags = ["manual"],
+ )
+
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/strict_action_env.patch b/third_party/nix/pkgs/bazel_8/patches/strict_action_env.patch
new file mode 100644
index 0000000..1402c20
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/strict_action_env.patch
@@ -0,0 +1,13 @@
+diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+index a70b5559bc..10bdffe961 100644
+--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
++++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+@@ -466,7 +466,7 @@ public class BazelRuleClassProvider {
+ // Note that --action_env does not propagate to the host config, so it is not a viable
+ // workaround when a genrule is itself built in the host config (e.g. nested genrules). See
+ // #8536.
+- return "/bin:/usr/bin:/usr/local/bin";
++ return "@strictActionEnvPatch@";
+ }
+
+ String newPath = "";
diff --git a/third_party/nix/pkgs/bazel_8/patches/trim-last-argument-to-gcc-if-empty.patch b/third_party/nix/pkgs/bazel_8/patches/trim-last-argument-to-gcc-if-empty.patch
new file mode 100644
index 0000000..b93b252
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/trim-last-argument-to-gcc-if-empty.patch
@@ -0,0 +1,37 @@
+From 177b4720d6fbaa7fdd17e5e11b2c79ac8f246786 Mon Sep 17 00:00:00 2001
+From: "Wael M. Nasreddine" <wael.nasreddine@gmail.com>
+Date: Thu, 27 Jun 2019 21:08:51 -0700
+Subject: [PATCH] Trim last argument to gcc if empty, on Darwin
+
+On Darwin, the last argument to GCC is coming up as an empty string.
+This is breaking the build of proto_library targets. However, I was not
+able to reproduce with the example cpp project[0].
+
+This commit removes the last argument if it's an empty string. This is
+not a problem on Linux.
+
+[0]: https://github.com/bazelbuild/examples/tree/master/cpp-tutorial/stage3
+---
+ tools/cpp/osx_cc_wrapper.sh.tpl | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/tools/cpp/osx_cc_wrapper.sh.tpl b/tools/cpp/osx_cc_wrapper.sh.tpl
+index 4c85cd9b6b..6c611e3d25 100644
+--- a/tools/cpp/osx_cc_wrapper.sh.tpl
++++ b/tools/cpp/osx_cc_wrapper.sh.tpl
+@@ -53,7 +53,11 @@ done
+ %{env}
+
+ # Call the C++ compiler
+-%{cc} "$@"
++if [[ ${*: -1} = "" ]]; then
++ %{cc} "${@:0:$#}"
++else
++ %{cc} "$@"
++fi
+
+ function get_library_path() {
+ for libdir in ${LIB_DIRS}; do
+--
+2.19.2
+
diff --git a/third_party/nix/pkgs/bazel_8/patches/usr_bin_env.patch b/third_party/nix/pkgs/bazel_8/patches/usr_bin_env.patch
new file mode 100644
index 0000000..0718b75
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/usr_bin_env.patch
@@ -0,0 +1,32 @@
+diff --git a/src/zip_builtins.sh b/src/zip_builtins.sh
+index d78ca5526a..c7d8f251cc 100755
+--- a/src/zip_builtins.sh
++++ b/src/zip_builtins.sh
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env bash
++#!@usrBinEnv@ bash
+
+ # Copyright 2020 The Bazel Authors. All rights reserved.
+ #
+
+diff --git a/src/zip_files.sh b/src/zip_files.sh
+index 1422a6c659..4b1c221784 100755
+--- a/src/zip_files.sh
++++ b/src/zip_files.sh
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env bash
++#!@usrBinEnv@ bash
+
+ # Copyright 2019 The Bazel Authors. All rights reserved.
+ #
+
+diff --git a/src/package-bazel.sh b/src/package-bazel.sh
+index 56e94db400..65fef20988 100755
+--- a/src/package-bazel.sh
++++ b/src/package-bazel.sh
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env bash
++#!@usrBinEnv@ bash
+ #
+ # Copyright 2015 The Bazel Authors. All rights reserved.
+ #
diff --git a/third_party/nix/pkgs/bazel_8/patches/xcode.patch b/third_party/nix/pkgs/bazel_8/patches/xcode.patch
new file mode 100644
index 0000000..52931a3
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/patches/xcode.patch
@@ -0,0 +1,31 @@
+diff --git a/scripts/bootstrap/compile.sh b/scripts/bootstrap/compile.sh
+index 1bad14cba7..d312fe08bb 100755
+--- a/scripts/bootstrap/compile.sh
++++ b/scripts/bootstrap/compile.sh
+@@ -402,7 +402,7 @@ cp $OUTPUT_DIR/libblaze.jar ${ARCHIVE_DIR}
+ # TODO(b/28965185): Remove when xcode-locator is no longer required in embedded_binaries.
+ log "Compiling xcode-locator..."
+ if [[ $PLATFORM == "darwin" ]]; then
+- run /usr/bin/xcrun --sdk macosx clang -mmacosx-version-min=10.13 -fobjc-arc -framework CoreServices -framework Foundation -o ${ARCHIVE_DIR}/xcode-locator tools/osx/xcode_locator.m
++ run @clangDarwin@ -mmacosx-version-min=10.13 -fobjc-arc -framework CoreServices -framework Foundation -o ${ARCHIVE_DIR}/xcode-locator tools/osx/xcode_locator.m
+ else
+ cp tools/osx/xcode_locator_stub.sh ${ARCHIVE_DIR}/xcode-locator
+ fi
+diff --git a/tools/osx/BUILD b/tools/osx/BUILD
+index 0358fb0ffe..1e6eae1f33 100644
+--- a/tools/osx/BUILD
++++ b/tools/osx/BUILD
+@@ -27,9 +27,9 @@ exports_files([
+ ])
+
+ DARWIN_XCODE_LOCATOR_COMPILE_COMMAND = """
+- /usr/bin/xcrun --sdk macosx clang -mmacosx-version-min=10.13 -fobjc-arc -framework CoreServices \
+- -framework Foundation -arch arm64 -arch x86_64 -Wl,-no_adhoc_codesign -Wl,-no_uuid -o $@ $< && \
+- env -i codesign --identifier $@ --force --sign - $@
++ @clangDarwin@ -mmacosx-version-min=10.13 -fobjc-arc -framework CoreServices \
++ -framework Foundation -Wl,-no_adhoc_codesign -Wl,-no_uuid -o $@ $< && \
++ @usrBinEnv@ @codesign@ --identifier $@ --force --sign - $@
+ """
+
+ genrule(
+
diff --git a/third_party/nix/pkgs/bazel_8/system.bazelrc b/third_party/nix/pkgs/bazel_8/system.bazelrc
new file mode 100644
index 0000000..6684e33
--- /dev/null
+++ b/third_party/nix/pkgs/bazel_8/system.bazelrc
@@ -0,0 +1,4 @@
+startup --server_javabase=@serverJavabase@
+
+# load default location for the system wide configuration
+try-import /etc/bazel.bazelrc