12 name ? "${args.pname}-${args.version}"
15 , bazelBuildFlags ? []
16 , bazelFetchFlags ? []
21 # Newer versions of Bazel are moving away from built-in rules_cc and instead
22 # allow fetching it as an external dependency in a WORKSPACE file[1]. If
23 # removed in the fixed-output fetch phase, building will fail to download it.
24 # This can be seen e.g. in #73097
26 # This option allows configuring the removal of rules_cc in cases where a
27 # project depends on it via an external dependency.
29 # [1]: https://github.com/bazelbuild/rules_cc
30 , removeRulesCC ? true
31 , removeLocalConfigCc ? true
34 # Use build --nobuild instead of fetch. This allows fetching the dependencies
35 # required for the build as configured, rather than fetching all the dependencies
36 # which may not work in some situations (e.g. Java code which ends up relying on
37 # Debian-specific /usr/share/java paths, but doesn't in the configured build).
38 , fetchConfigured ? false
40 # Don’t add Bazel --copt and --linkopt from NIX_CFLAGS_COMPILE /
41 # NIX_LDFLAGS. This is necessary when using a custom toolchain which
42 # Bazel wants all headers / libraries to come from, like when using
43 # CROSSTOOL. Weirdly, we can still get the flags through the wrapped
45 , dontAddBazelOpts ? false
50 fArgs = removeAttrs args [ "buildAttrs" "fetchAttrs" "removeRulesCC" ];
51 fBuildAttrs = fArgs // buildAttrs;
52 fFetchAttrs = fArgs // removeAttrs fetchAttrs [ "sha256" ];
54 in stdenv.mkDerivation (fBuildAttrs // {
55 inherit name bazelFlags bazelBuildFlags bazelFetchFlags bazelTarget;
57 deps = stdenv.mkDerivation (fFetchAttrs // {
58 name = "${name}-deps.tar.gz";
59 inherit bazelFlags bazelBuildFlags bazelFetchFlags bazelTarget;
61 impureEnvVars = lib.fetchers.proxyImpureEnvVars;
63 nativeBuildInputs = fFetchAttrs.nativeBuildInputs or [] ++ [ bazel ];
65 preHook = fFetchAttrs.preHook or "" + ''
66 export bazelOut="$(echo ''${NIX_BUILD_TOP}/output | sed -e 's,//,/,g')"
67 export bazelUserRoot="$(echo ''${NIX_BUILD_TOP}/tmp | sed -e 's,//,/,g')"
68 export HOME="$NIX_BUILD_TOP"
70 # This is needed for git_repository with https remotes
71 export GIT_SSL_CAINFO="${cacert}/etc/ssl/certs/ca-bundle.crt"
72 # This is needed for Bazel fetchers that are themselves programs (e.g.
73 # rules_go using the go toolchain)
74 export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
77 buildPhase = fFetchAttrs.buildPhase or ''
80 # Bazel computes the default value of output_user_root before parsing the
81 # flag. The computation of the default value involves getting the $USER
82 # from the environment. I don't have that variable when building with
83 # sandbox enabled. Code here
84 # https://github.com/bazelbuild/bazel/blob/9323c57607d37f9c949b60e293b573584906da46/src/main/cpp/startup_options.cc#L123-L124
86 # On macOS Bazel will use the system installed Xcode or CLT toolchain instead of the one in the PATH unless we pass BAZEL_USE_CPP_ONLY_TOOLCHAIN
88 # We disable multithreading for the fetching phase since it can lead to timeouts with many dependencies/threads:
89 # https://github.com/bazelbuild/bazel/issues/6502
90 BAZEL_USE_CPP_ONLY_TOOLCHAIN=1 \
91 USER=homeless-shelter \
93 --output_base="$bazelOut" \
94 --output_user_root="$bazelUserRoot" \
95 ${if fetchConfigured then "build --nobuild" else "fetch"} \
96 --loading_phase_threads=1 \
104 installPhase = fFetchAttrs.installPhase or ''
107 # Remove all built in external workspaces, Bazel will recreate them when building
108 rm -rf $bazelOut/external/{bazel_tools,\@bazel_tools.marker}
109 ${if removeRulesCC then "rm -rf $bazelOut/external/{rules_cc,\\@rules_cc.marker}" else ""}
110 rm -rf $bazelOut/external/{embedded_jdk,\@embedded_jdk.marker}
111 ${if removeLocalConfigCc then "rm -rf $bazelOut/external/{local_config_cc,\\@local_config_cc.marker}" else ""}
112 ${if removeLocal then "rm -rf $bazelOut/external/{local_*,\\@local_*.marker}" else ""}
115 find $bazelOut/external -name '@*\.marker' -exec sh -c 'echo > {}' \;
117 # Remove all vcs files
118 rm -rf $(find $bazelOut/external -type d -name .git)
119 rm -rf $(find $bazelOut/external -type d -name .svn)
120 rm -rf $(find $bazelOut/external -type d -name .hg)
122 # Removing top-level symlinks along with their markers.
123 # This is needed because they sometimes point to temporary paths (?).
124 # For example, in Tensorflow-gpu build:
125 # platforms -> NIX_BUILD_TOP/tmp/install/35282f5123611afa742331368e9ae529/_embedded_binaries/platforms
126 find $bazelOut/external -maxdepth 1 -type l | while read symlink; do
127 name="$(basename "$symlink")"
129 test -f "$bazelOut/external/@$name.marker" && rm "$bazelOut/external/@$name.marker"
132 # Patching symlinks to remove build directory reference
133 find $bazelOut/external -type l | while read symlink; do
134 new_target="$(readlink "$symlink" | sed "s,$NIX_BUILD_TOP,NIX_BUILD_TOP,")"
136 ln -sf "$new_target" "$symlink"
139 echo '${bazel.name}' > $bazelOut/external/.nix-bazel-version
141 (cd $bazelOut/ && tar czf $out --sort=name --mtime='@1' --owner=0 --group=0 --numeric-owner external/)
147 allowedRequisites = [];
149 outputHashAlgo = "sha256";
150 outputHash = fetchAttrs.sha256;
153 nativeBuildInputs = fBuildAttrs.nativeBuildInputs or [] ++ [ (bazel.override { enableNixHacks = true; }) ];
155 preHook = fBuildAttrs.preHook or "" + ''
156 export bazelOut="$NIX_BUILD_TOP/output"
157 export bazelUserRoot="$NIX_BUILD_TOP/tmp"
158 export HOME="$NIX_BUILD_TOP"
164 (cd $bazelOut && tar xfz $deps)
166 test "${bazel.name}" = "$(<$bazelOut/external/.nix-bazel-version)" || {
167 echo "fixed output derivation was built for a different bazel version" >&2
168 echo " got: $(<$bazelOut/external/.nix-bazel-version)" >&2
169 echo "expected: ${bazel.name}" >&2
173 chmod -R +w $bazelOut
174 find $bazelOut -type l | while read symlink; do
175 if [[ $(readlink "$symlink") == *NIX_BUILD_TOP* ]]; then
176 ln -sf $(readlink "$symlink" | sed "s,NIX_BUILD_TOP,$NIX_BUILD_TOP,") "$symlink"
179 '' + fBuildAttrs.preConfigure or "";
181 inherit dontAddBazelOpts;
183 buildPhase = fBuildAttrs.buildPhase or ''
186 # Bazel sandboxes the execution of the tools it invokes, so even though we are
187 # calling the correct nix wrappers, the values of the environment variables
188 # the wrappers are expecting will not be set. So instead of relying on the
189 # wrappers picking them up, pass them in explicitly via `--copt`, `--linkopt`
196 if [ -z "''${dontAddBazelOpts:-}" ]; then
197 for flag in $NIX_CFLAGS_COMPILE; do
198 copts+=( "--copt=$flag" )
199 host_copts+=( "--host_copt=$flag" )
201 for flag in $NIX_CXXSTDLIB_COMPILE; do
202 copts+=( "--copt=$flag" )
203 host_copts+=( "--host_copt=$flag" )
205 for flag in $NIX_LDFLAGS; do
206 linkopts+=( "--linkopt=-Wl,$flag" )
207 host_linkopts+=( "--host_linkopt=-Wl,$flag" )
211 BAZEL_USE_CPP_ONLY_TOOLCHAIN=1 \
212 USER=homeless-shelter \
214 --output_base="$bazelOut" \
215 --output_user_root="$bazelUserRoot" \
217 -j $NIX_BUILD_CORES \
219 "''${host_copts[@]}" \
221 "''${host_linkopts[@]}" \