| Tim Windelschmidt | 5d357d8 | 2025-07-10 18:47:15 +0200 | [diff] [blame^] | 1 | { stdenv |
| 2 | , callPackage |
| 3 | , # nix tooling and utilities |
| 4 | darwin |
| 5 | , lib |
| 6 | , fetchzip |
| 7 | , fetchpatch |
| 8 | , makeWrapper |
| 9 | , writeTextFile |
| 10 | , replaceVars |
| 11 | , # native build inputs |
| 12 | runtimeShell |
| 13 | , zip |
| 14 | , unzip |
| 15 | , bash |
| 16 | , coreutils |
| 17 | , which |
| 18 | , gawk |
| 19 | , gnused |
| 20 | , gnutar |
| 21 | , gnugrep |
| 22 | , gzip |
| 23 | , findutils |
| 24 | , diffutils |
| 25 | , gnupatch |
| 26 | , file |
| 27 | , installShellFiles |
| 28 | , python3 |
| 29 | , # Apple dependencies |
| 30 | cctools |
| 31 | , # Allow to independently override the jdks used to build and run respectively |
| 32 | jdk_headless |
| 33 | , # Toggle for hacks for running bazel under buildBazelPackage: |
| 34 | # Always assume all markers valid (this is needed because we remove markers; they are non-deterministic). |
| 35 | # Also, don't clean up environment variables (so that NIX_ environment variables are passed to compilers). |
| 36 | version ? "8.3.1" |
| 37 | , |
| 38 | }: |
| 39 | |
| 40 | let |
| 41 | inherit (callPackage ./build-support/patching.nix { }) addFilePatch; |
| 42 | inherit (stdenv.hostPlatform) isDarwin isAarch64; |
| 43 | |
| 44 | bazelSystem = if isDarwin then "darwin" else "linux"; |
| 45 | |
| 46 | # on aarch64 Darwin, `uname -m` returns "arm64" |
| 47 | bazelArch = if isDarwin && isAarch64 then "arm64" else stdenv.hostPlatform.parsed.cpu.name; |
| 48 | |
| 49 | src = fetchzip { |
| 50 | url = "https://github.com/bazelbuild/bazel/releases/download/${version}/bazel-${version}-dist.zip"; |
| 51 | hash = "sha256-Hiny31S+YF7JdKjxzCyKdw3J/3OdDwsKeOkppfvWrNI="; |
| 52 | stripRoot = false; |
| 53 | }; |
| 54 | |
| 55 | defaultShellUtils = |
| 56 | # Keep this list conservative. For more exotic tools, prefer to use |
| 57 | # @rules_nixpkgs to pull in tools from the nix repository. Example: |
| 58 | # |
| 59 | # WORKSPACE: |
| 60 | # |
| 61 | # nixpkgs_git_repository( |
| 62 | # name = "nixpkgs", |
| 63 | # revision = "def5124ec8367efdba95a99523dd06d918cb0ae8", |
| 64 | # ) |
| 65 | # |
| 66 | # # This defines an external Bazel workspace. |
| 67 | # nixpkgs_package( |
| 68 | # name = "bison", |
| 69 | # repositories = { "nixpkgs": "@nixpkgs//:default.nix" }, |
| 70 | # ) |
| 71 | # |
| 72 | # some/BUILD.bazel: |
| 73 | # |
| 74 | # genrule( |
| 75 | # ... |
| 76 | # cmd = "$(location @bison//:bin/bison) -other -args", |
| 77 | # tools = [ |
| 78 | # ... |
| 79 | # "@bison//:bin/bison", |
| 80 | # ], |
| 81 | # ) |
| 82 | [ |
| 83 | coreutils |
| 84 | diffutils |
| 85 | file |
| 86 | findutils |
| 87 | gawk |
| 88 | gnugrep |
| 89 | gnupatch |
| 90 | gnused |
| 91 | gnutar |
| 92 | gzip |
| 93 | unzip |
| 94 | which |
| 95 | zip |
| 96 | bash |
| 97 | ]; |
| 98 | defaultShell = callPackage ./defaultShell.nix { } { inherit defaultShellUtils; }; |
| 99 | |
| 100 | commandArgs = |
| 101 | [ |
| 102 | "--nobuild_python_zip" |
| 103 | "--features=-module_maps" |
| 104 | "--host_features=-module_maps" |
| 105 | "--announce_rc" |
| 106 | "--verbose_failures" |
| 107 | "--curses=no" |
| 108 | ] |
| 109 | ++ lib.optionals (isDarwin) [ |
| 110 | "--macos_sdk_version=${stdenv.hostPlatform.darwinMinVersion}" |
| 111 | "--cxxopt=-isystem" |
| 112 | "--cxxopt=${lib.getDev stdenv.cc.libcxx}/include/c++/v1" |
| 113 | "--host_cxxopt=-isystem" |
| 114 | "--host_cxxopt=${lib.getDev stdenv.cc.libcxx}/include/c++/v1" |
| 115 | "--copt=-isystem" |
| 116 | "--copt=${lib.getDev darwin.libresolv}/include" |
| 117 | "--host_copt=-isystem" |
| 118 | "--host_copt=${lib.getDev darwin.libresolv}/include" |
| 119 | ]; |
| 120 | |
| 121 | in |
| 122 | stdenv.mkDerivation rec { |
| 123 | pname = "bazel"; |
| 124 | inherit version src; |
| 125 | |
| 126 | darwinPatches = [ |
| 127 | # Bazel integrates with apple IOKit to inhibit and track system sleep. |
| 128 | # Inside the darwin sandbox, these API calls are blocked, and bazel |
| 129 | # crashes. It seems possible to allow these APIs inside the sandbox, but it |
| 130 | # feels simpler to patch bazel not to use it at all. So our bazel is |
| 131 | # incapable of preventing system sleep, which is a small price to pay to |
| 132 | # guarantee that it will always run in any nix context. |
| 133 | # |
| 134 | # See also ./bazel_darwin_sandbox.patch in bazel_5. That patch uses |
| 135 | # NIX_BUILD_TOP env var to conditionnally disable sleep features inside the |
| 136 | # sandbox. |
| 137 | # |
| 138 | # If you want to investigate the sandbox profile path, |
| 139 | # IORegisterForSystemPower can be allowed with |
| 140 | # |
| 141 | # propagatedSandboxProfile = '' |
| 142 | # (allow iokit-open (iokit-user-client-class "RootDomainUserClient")) |
| 143 | # ''; |
| 144 | # |
| 145 | # I do not know yet how to allow IOPMAssertion{CreateWithName,Release} |
| 146 | ./patches/darwin_sleep.patch |
| 147 | |
| 148 | # Fix DARWIN_XCODE_LOCATOR_COMPILE_COMMAND by removing multi-arch support. |
| 149 | # Nixpkgs toolcahins do not support that (yet?) and get confused. |
| 150 | # Also add an explicit /usr/bin prefix that will be patched below. |
| 151 | (replaceVars ./patches/xcode.patch { |
| 152 | usrBinEnv = "${coreutils}/bin/env"; |
| 153 | clangDarwin = "${stdenv.cc}/bin/clang"; |
| 154 | codesign = "${darwin.sigtool}/bin/codesign"; |
| 155 | }) |
| 156 | |
| 157 | # Revert preference for apple_support over rules_cc toolchain for now |
| 158 | # will need to figure out how to build with apple_support toolchain later |
| 159 | ./patches/apple_cc_toolchain.patch |
| 160 | |
| 161 | # On Darwin, the last argument to gcc is coming up as an empty string. i.e: '' |
| 162 | # This is breaking the build of any C target. This patch removes the last |
| 163 | # argument if it's found to be an empty string. |
| 164 | ./patches/trim-last-argument-to-gcc-if-empty.patch |
| 165 | |
| 166 | # fdopen() compilation fix |
| 167 | (fetchpatch { |
| 168 | url = "https://github.com/madler/zlib/commit/4bd9a71f3539b5ce47f0c67ab5e01f3196dc8ef9.patch"; |
| 169 | hash = "sha256-wlZY0/XqND5Fk+SJkUCUj7XhGVwUJw/VqVGAlDdqOhs="; |
| 170 | stripLen = 1; |
| 171 | extraPrefix = "third_party/zlib/"; |
| 172 | }) |
| 173 | ]; |
| 174 | |
| 175 | patches = lib.optionals isDarwin darwinPatches ++ [ |
| 176 | # patch that propagates rules_* patches below |
| 177 | # patches need to be within source root and can't be absolute paths in Nix store |
| 178 | # so rules_* patches are injected via addFilePatch |
| 179 | ./patches/deps_patches.patch |
| 180 | (addFilePatch { |
| 181 | path = "b/third_party/rules_python.patch"; |
| 182 | file = replaceVars ./patches/rules_python.patch { |
| 183 | usrBinEnv = "${coreutils}/bin/env"; |
| 184 | }; |
| 185 | }) |
| 186 | (addFilePatch { |
| 187 | path = "b/third_party/rules_java.patch"; |
| 188 | file = replaceVars ./patches/rules_java.patch { |
| 189 | defaultBash = "${defaultShell.bashWithDefaultShellUtils}/bin/bash"; |
| 190 | }; |
| 191 | }) |
| 192 | # Suggested for upstream in https://github.com/bazelbuild/bazel/pull/25936 |
| 193 | ./patches/build_execlog_parser.patch |
| 194 | # Part of suggestion for upstream in https://github.com/bazelbuild/bazel/pull/25934 |
| 195 | ./patches/env_bash.patch |
| 196 | # Suggested for upstream in https://github.com/bazelbuild/bazel/pull/25935 |
| 197 | ./patches/gen_completion.patch |
| 198 | |
| 199 | # --experimental_strict_action_env (which may one day become the default |
| 200 | # see bazelbuild/bazel#2574) hardcodes the default |
| 201 | # action environment to a non hermetic value (e.g. "/usr/local/bin"). |
| 202 | # This is non hermetic on non-nixos systems. On NixOS, bazel cannot find the required binaries. |
| 203 | # So we are replacing this bazel paths by defaultShellPath, |
| 204 | # improving hermeticity and making it work in nixos. |
| 205 | (replaceVars ./patches/strict_action_env.patch { |
| 206 | strictActionEnvPatch = defaultShell.defaultShellPath; |
| 207 | }) |
| 208 | |
| 209 | (replaceVars ./patches/default_bash.patch { |
| 210 | defaultBash = "${defaultShell.bashWithDefaultShellUtils}/bin/bash"; |
| 211 | }) |
| 212 | |
| 213 | (replaceVars ./patches/md5sum.patch { |
| 214 | md5sum = "${coreutils}/bin/md5sum"; |
| 215 | }) |
| 216 | |
| 217 | # Nix build sandbox can configure custom PATH but doesn't have |
| 218 | # /usr/bin/env which is unfortunate https://github.com/NixOS/nixpkgs/issues/6227 |
| 219 | # and we need to do a silly patch |
| 220 | (replaceVars ./patches/usr_bin_env.patch { |
| 221 | usrBinEnv = "${coreutils}/bin/env"; |
| 222 | }) |
| 223 | |
| 224 | # Provide default JRE for Bazel process by setting --server_javabase= |
| 225 | # in a new default system bazelrc file |
| 226 | (replaceVars ./patches/bazel_rc.patch { |
| 227 | bazelSystemBazelRCPath = replaceVars ./system.bazelrc { |
| 228 | serverJavabase = jdk_headless; |
| 229 | }; |
| 230 | }) |
| 231 | ]; |
| 232 | |
| 233 | meta = with lib; { |
| 234 | homepage = "https://github.com/bazelbuild/bazel/"; |
| 235 | description = "Build tool that builds code quickly and reliably"; |
| 236 | sourceProvenance = with sourceTypes; [ |
| 237 | fromSource |
| 238 | binaryBytecode # source bundles dependencies as jars |
| 239 | ]; |
| 240 | license = licenses.asl20; |
| 241 | teams = [ lib.teams.bazel ]; |
| 242 | mainProgram = "bazel"; |
| 243 | platforms = lib.platforms.linux ++ lib.platforms.darwin; |
| 244 | }; |
| 245 | |
| 246 | nativeBuildInputs = |
| 247 | [ |
| 248 | makeWrapper |
| 249 | jdk_headless |
| 250 | python3 |
| 251 | unzip |
| 252 | which |
| 253 | |
| 254 | # Shell completion |
| 255 | installShellFiles |
| 256 | python3.pkgs.absl-py # Needed to build fish completion |
| 257 | ] |
| 258 | # Needed for execlog |
| 259 | ++ lib.optional (!stdenv.hostPlatform.isDarwin) stdenv.cc |
| 260 | ++ lib.optional (stdenv.hostPlatform.isDarwin) cctools; |
| 261 | |
| 262 | buildPhase = '' |
| 263 | runHook preBuild |
| 264 | export HOME=$(mktemp -d) |
| 265 | |
| 266 | # If EMBED_LABEL isn't set, it'd be auto-detected from CHANGELOG.md |
| 267 | # and `git rev-parse --short HEAD` which would result in |
| 268 | # "3.7.0- (@non-git)" due to non-git build and incomplete changelog. |
| 269 | # Actual bazel releases use scripts/release/common.sh which is based |
| 270 | # on branch/tag information which we don't have with tarball releases. |
| 271 | # Note that .bazelversion is always correct and is based on bazel-* |
| 272 | # executable name, version checks should work fine |
| 273 | export EMBED_LABEL="${version}" |
| 274 | |
| 275 | echo "Stage 1 - Running bazel bootstrap script" |
| 276 | export EXTRA_BAZEL_ARGS="${lib.strings.concatStringsSep " " commandArgs}" |
| 277 | |
| 278 | ${bash}/bin/bash ./compile.sh |
| 279 | |
| 280 | # XXX: get rid of this, or move it to another stage. |
| 281 | # It is plain annoying when builds fail. |
| 282 | echo "Stage 2 - Generate bazel completions" |
| 283 | ${bash}/bin/bash ./scripts/generate_bash_completion.sh \ |
| 284 | --bazel=./output/bazel \ |
| 285 | --output=./output/bazel-complete.bash \ |
| 286 | --prepend=./scripts/bazel-complete-header.bash \ |
| 287 | --prepend=./scripts/bazel-complete-template.bash |
| 288 | ${python3}/bin/python3 ./scripts/generate_fish_completion.py \ |
| 289 | --bazel=./output/bazel \ |
| 290 | --output=./output/bazel-complete.fish |
| 291 | |
| 292 | runHook postBuild |
| 293 | ''; |
| 294 | |
| 295 | installPhase = '' |
| 296 | runHook preInstall |
| 297 | |
| 298 | # Bazel binary contains zip archive, which contains text files and a jar |
| 299 | # both of which can have store references that might be obscured to Nix |
| 300 | # builder in packaged form, so we unpack and extract those references |
| 301 | |
| 302 | # Note: grep isn't necessarily 100% accurate, other approaches could be |
| 303 | # to disassemble Jar (slow) or hardcode known references |
| 304 | mkdir -p $out/nix-support |
| 305 | INSTALL_BASE=$(./output/bazel --batch info install_base) |
| 306 | find "$INSTALL_BASE" -type f -exec \ |
| 307 | ${gnugrep}/bin/grep --text --only-matching --no-filename "$NIX_STORE/[^/]*" '{}' \; \ |
| 308 | | sort -u >> $out/nix-support/depends |
| 309 | |
| 310 | mkdir -p $out/bin |
| 311 | |
| 312 | # official wrapper scripts that searches for $WORKSPACE_ROOT/tools/bazel if |
| 313 | # it can’t find something in tools, it calls |
| 314 | # $out/bin/bazel-{version}-{os_arch} The binary _must_ exist with this |
| 315 | # naming if your project contains a .bazelversion file. |
| 316 | cp ./scripts/packages/bazel.sh $out/bin/bazel |
| 317 | versioned_bazel="$out/bin/bazel-${version}-${bazelSystem}-${bazelArch}" |
| 318 | mv ./output/bazel "$versioned_bazel" |
| 319 | wrapProgram "$versioned_bazel" --suffix PATH : ${defaultShell.defaultShellPath} |
| 320 | |
| 321 | mkdir $out/share |
| 322 | cp ./output/parser_deploy.jar $out/share/parser_deploy.jar |
| 323 | substitute ${./bazel-execlog.sh} $out/bin/bazel-execlog \ |
| 324 | --subst-var out \ |
| 325 | --subst-var-by runtimeShell ${runtimeShell} \ |
| 326 | --subst-var-by javaBin ${jdk_headless}/bin/java |
| 327 | chmod +x $out/bin/bazel-execlog |
| 328 | |
| 329 | # shell completion files |
| 330 | installShellCompletion --bash \ |
| 331 | --name bazel.bash \ |
| 332 | ./output/bazel-complete.bash |
| 333 | installShellCompletion --zsh \ |
| 334 | --name _bazel \ |
| 335 | ./scripts/zsh_completion/_bazel |
| 336 | installShellCompletion --fish \ |
| 337 | --name bazel.fish \ |
| 338 | ./output/bazel-complete.fish |
| 339 | ''; |
| 340 | |
| 341 | postFixup = |
| 342 | # verify that bazel binary still works post-fixup |
| 343 | '' |
| 344 | USE_BAZEL_VERSION=${version} $out/bin/bazel --batch info release |
| 345 | ''; |
| 346 | |
| 347 | # Bazel binary includes zip archive at the end that `strip` would end up discarding |
| 348 | stripExclude = [ "bin/.bazel-${version}-*-wrapped" ]; |
| 349 | |
| 350 | passthru = { |
| 351 | tests = { |
| 352 | inherit (callPackage ./examples.nix { }) cpp java rust; |
| 353 | }; |
| 354 | }; |
| 355 | } |