blob: ab053846d721c0c582783c3680a4c5d7decd7d63 [file] [log] [blame]
Tim Windelschmidt5d357d82025-07-10 18:47:15 +02001{ 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
40let
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
121in
122stdenv.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
Leopold Schabel5a4037c2025-07-21 18:27:05 +0200224 # TODO: upstream to nixpkgs
225 # Bazel tries to run "/bin/true" to test if linux-sandbox works.
226 (replaceVars ./patches/linux_sandbox.patch {
227 binTrue = "${coreutils}/bin/true";
228 })
229
Tim Windelschmidt5d357d82025-07-10 18:47:15 +0200230 # Provide default JRE for Bazel process by setting --server_javabase=
231 # in a new default system bazelrc file
232 (replaceVars ./patches/bazel_rc.patch {
233 bazelSystemBazelRCPath = replaceVars ./system.bazelrc {
234 serverJavabase = jdk_headless;
235 };
236 })
237 ];
238
239 meta = with lib; {
240 homepage = "https://github.com/bazelbuild/bazel/";
241 description = "Build tool that builds code quickly and reliably";
242 sourceProvenance = with sourceTypes; [
243 fromSource
244 binaryBytecode # source bundles dependencies as jars
245 ];
246 license = licenses.asl20;
247 teams = [ lib.teams.bazel ];
248 mainProgram = "bazel";
249 platforms = lib.platforms.linux ++ lib.platforms.darwin;
250 };
251
252 nativeBuildInputs =
253 [
254 makeWrapper
255 jdk_headless
256 python3
257 unzip
258 which
259
260 # Shell completion
261 installShellFiles
262 python3.pkgs.absl-py # Needed to build fish completion
263 ]
264 # Needed for execlog
265 ++ lib.optional (!stdenv.hostPlatform.isDarwin) stdenv.cc
266 ++ lib.optional (stdenv.hostPlatform.isDarwin) cctools;
267
268 buildPhase = ''
269 runHook preBuild
270 export HOME=$(mktemp -d)
271
272 # If EMBED_LABEL isn't set, it'd be auto-detected from CHANGELOG.md
273 # and `git rev-parse --short HEAD` which would result in
274 # "3.7.0- (@non-git)" due to non-git build and incomplete changelog.
275 # Actual bazel releases use scripts/release/common.sh which is based
276 # on branch/tag information which we don't have with tarball releases.
277 # Note that .bazelversion is always correct and is based on bazel-*
278 # executable name, version checks should work fine
279 export EMBED_LABEL="${version}"
280
281 echo "Stage 1 - Running bazel bootstrap script"
282 export EXTRA_BAZEL_ARGS="${lib.strings.concatStringsSep " " commandArgs}"
283
284 ${bash}/bin/bash ./compile.sh
285
286 # XXX: get rid of this, or move it to another stage.
287 # It is plain annoying when builds fail.
288 echo "Stage 2 - Generate bazel completions"
289 ${bash}/bin/bash ./scripts/generate_bash_completion.sh \
290 --bazel=./output/bazel \
291 --output=./output/bazel-complete.bash \
292 --prepend=./scripts/bazel-complete-header.bash \
293 --prepend=./scripts/bazel-complete-template.bash
294 ${python3}/bin/python3 ./scripts/generate_fish_completion.py \
295 --bazel=./output/bazel \
296 --output=./output/bazel-complete.fish
297
298 runHook postBuild
299 '';
300
301 installPhase = ''
302 runHook preInstall
303
304 # Bazel binary contains zip archive, which contains text files and a jar
305 # both of which can have store references that might be obscured to Nix
306 # builder in packaged form, so we unpack and extract those references
307
308 # Note: grep isn't necessarily 100% accurate, other approaches could be
309 # to disassemble Jar (slow) or hardcode known references
310 mkdir -p $out/nix-support
311 INSTALL_BASE=$(./output/bazel --batch info install_base)
312 find "$INSTALL_BASE" -type f -exec \
313 ${gnugrep}/bin/grep --text --only-matching --no-filename "$NIX_STORE/[^/]*" '{}' \; \
314 | sort -u >> $out/nix-support/depends
315
316 mkdir -p $out/bin
317
318 # official wrapper scripts that searches for $WORKSPACE_ROOT/tools/bazel if
319 # it can’t find something in tools, it calls
320 # $out/bin/bazel-{version}-{os_arch} The binary _must_ exist with this
321 # naming if your project contains a .bazelversion file.
322 cp ./scripts/packages/bazel.sh $out/bin/bazel
323 versioned_bazel="$out/bin/bazel-${version}-${bazelSystem}-${bazelArch}"
324 mv ./output/bazel "$versioned_bazel"
325 wrapProgram "$versioned_bazel" --suffix PATH : ${defaultShell.defaultShellPath}
326
327 mkdir $out/share
328 cp ./output/parser_deploy.jar $out/share/parser_deploy.jar
329 substitute ${./bazel-execlog.sh} $out/bin/bazel-execlog \
330 --subst-var out \
331 --subst-var-by runtimeShell ${runtimeShell} \
332 --subst-var-by javaBin ${jdk_headless}/bin/java
333 chmod +x $out/bin/bazel-execlog
334
335 # shell completion files
336 installShellCompletion --bash \
337 --name bazel.bash \
338 ./output/bazel-complete.bash
339 installShellCompletion --zsh \
340 --name _bazel \
341 ./scripts/zsh_completion/_bazel
342 installShellCompletion --fish \
343 --name bazel.fish \
344 ./output/bazel-complete.fish
345 '';
346
347 postFixup =
348 # verify that bazel binary still works post-fixup
349 ''
350 USE_BAZEL_VERSION=${version} $out/bin/bazel --batch info release
351 '';
352
353 # Bazel binary includes zip archive at the end that `strip` would end up discarding
354 stripExclude = [ "bin/.bazel-${version}-*-wrapped" ];
355
356 passthru = {
357 tests = {
358 inherit (callPackage ./examples.nix { }) cpp java rust;
359 };
360 };
361}