btrbk: add mainProgram (#356350)
[NixPkgs.git] / pkgs / stdenv / generic / setup.sh
blob72fdbef981da804c7710184c68571fa3cc705e55
1 # shellcheck shell=bash
2 # shellcheck disable=1090,2154,2123,2034,2178,2048,2068,1091
3 __nixpkgs_setup_set_original=$-
4 set -eu
5 set -o pipefail
7 if [[ -n "${BASH_VERSINFO-}" && "${BASH_VERSINFO-}" -lt 5 ]]; then
8 echo "Detected Bash version that isn't supported by Nixpkgs (${BASH_VERSION})"
9 echo "Please install Bash 5 or greater to continue."
10 exit 1
13 shopt -s inherit_errexit
15 # $NIX_DEBUG must be a documented integer level, if set, so we can use it safely as an integer.
16 # See the `Verbosity` enum in the Nix source for these levels.
17 if ! [[ -z ${NIX_DEBUG-} || $NIX_DEBUG == [0-7] ]]; then
18 # shellcheck disable=SC2016
19 printf 'The `NIX_DEBUG` environment variable has an unexpected value: %s\n' "${NIX_DEBUG}"
20 echo "It can only be unset or an integer between 0 and 7."
21 exit 1
24 if [[ ${NIX_DEBUG:-0} -ge 6 ]]; then
25 set -x
28 if [ -f .attrs.sh ] || [[ -n "${NIX_ATTRS_JSON_FILE:-}" ]]; then
29 __structuredAttrs=1
30 echo "structuredAttrs is enabled"
32 for outputName in "${!outputs[@]}"; do
33 # ex: out=/nix/store/...
34 export "$outputName=${outputs[$outputName]}"
35 done
37 # $NIX_ATTRS_JSON_FILE pointed to the wrong location in sandbox
38 # https://github.com/NixOS/nix/issues/6736; please keep around until the
39 # fix reaches *every patch version* that's >= lib/minver.nix
40 if ! [[ -e "${NIX_ATTRS_JSON_FILE:-}" ]]; then
41 export NIX_ATTRS_JSON_FILE="$NIX_BUILD_TOP/.attrs.json"
43 if ! [[ -e "${NIX_ATTRS_SH_FILE:-}" ]]; then
44 export NIX_ATTRS_SH_FILE="$NIX_BUILD_TOP/.attrs.sh"
46 else
47 __structuredAttrs=
48 : "${outputs:=out}"
51 getAllOutputNames() {
52 if [ -n "$__structuredAttrs" ]; then
53 echo "${!outputs[*]}"
54 else
55 echo "$outputs"
59 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
60 # Corresponds to `Verbosity::lvlError` in the Nix source.
61 nixErrorLog() {
62 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 0 ]]; then return; fi
63 printf "%s\n" "$*" >&"$NIX_LOG_FD"
66 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
67 # Corresponds to `Verbosity::lvlWarn` in the Nix source.
68 nixWarnLog() {
69 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 1 ]]; then return; fi
70 printf "%s\n" "$*" >&"$NIX_LOG_FD"
73 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
74 # Corresponds to `Verbosity::lvlNotice` in the Nix source.
75 nixNoticeLog() {
76 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 2 ]]; then return; fi
77 printf "%s\n" "$*" >&"$NIX_LOG_FD"
80 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
81 # Corresponds to `Verbosity::lvlInfo` in the Nix source.
82 nixInfoLog() {
83 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 3 ]]; then return; fi
84 printf "%s\n" "$*" >&"$NIX_LOG_FD"
87 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
88 # Corresponds to `Verbosity::lvlTalkative` in the Nix source.
89 nixTalkativeLog() {
90 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 4 ]]; then return; fi
91 printf "%s\n" "$*" >&"$NIX_LOG_FD"
94 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
95 # Corresponds to `Verbosity::lvlChatty` in the Nix source.
96 nixChattyLog() {
97 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 5 ]]; then return; fi
98 printf "%s\n" "$*" >&"$NIX_LOG_FD"
101 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
102 # Corresponds to `Verbosity::lvlDebug` in the Nix source.
103 nixDebugLog() {
104 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 6 ]]; then return; fi
105 printf "%s\n" "$*" >&"$NIX_LOG_FD"
108 # All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set.
109 # Corresponds to `Verbosity::lvlVomit` in the Nix source.
110 nixVomitLog() {
111 if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 7 ]]; then return; fi
112 printf "%s\n" "$*" >&"$NIX_LOG_FD"
115 # Log a hook, to be run before the hook is actually called.
116 # logging for "implicit" hooks -- the ones specified directly
117 # in derivation's arguments -- is done in _callImplicitHook instead.
118 _logHook() {
119 # Fast path in case nixTalkativeLog is no-op.
120 if [[ -z ${NIX_LOG_FD-} ]]; then
121 return
124 local hookKind="$1"
125 local hookExpr="$2"
126 shift 2
128 if declare -F "$hookExpr" > /dev/null 2>&1; then
129 nixTalkativeLog "calling '$hookKind' function hook '$hookExpr'" "$@"
130 elif type -p "$hookExpr" > /dev/null; then
131 nixTalkativeLog "sourcing '$hookKind' script hook '$hookExpr'"
132 elif [[ "$hookExpr" != "_callImplicitHook"* ]]; then
133 # Here we have a string hook to eval.
134 # Join lines onto one with literal \n characters unless NIX_DEBUG >= 5.
135 local exprToOutput
136 if [[ ${NIX_DEBUG:-0} -ge 5 ]]; then
137 exprToOutput="$hookExpr"
138 else
139 # We have `r'\n'.join([line.lstrip() for lines in text.split('\n')])` at home.
140 local hookExprLine
141 while IFS= read -r hookExprLine; do
142 # These lines often have indentation,
143 # so let's remove leading whitespace.
144 hookExprLine="${hookExprLine#"${hookExprLine%%[![:space:]]*}"}"
145 # If this line wasn't entirely whitespace,
146 # then add it to our output
147 if [[ -n "$hookExprLine" ]]; then
148 exprToOutput+="$hookExprLine\\n "
150 done <<< "$hookExpr"
152 # And then remove the final, unnecessary, \n
153 exprToOutput="${exprToOutput%%\\n }"
155 nixTalkativeLog "evaling '$hookKind' string hook '$exprToOutput'"
159 ######################################################################
160 # Hook handling.
162 # Run all hooks with the specified name in the order in which they
163 # were added, stopping if any fails (returns a non-zero exit
164 # code). The hooks for <hookName> are the shell function or variable
165 # <hookName>, and the values of the shell array ‘<hookName>Hooks’.
166 runHook() {
167 local hookName="$1"
168 shift
169 local hooksSlice="${hookName%Hook}Hooks[@]"
171 local hook
172 # Hack around old bash being bad and thinking empty arrays are
173 # undefined.
174 for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do
175 _logHook "$hookName" "$hook" "$@"
176 _eval "$hook" "$@"
177 done
179 return 0
183 # Run all hooks with the specified name, until one succeeds (returns a
184 # zero exit code). If none succeed, return a non-zero exit code.
185 runOneHook() {
186 local hookName="$1"
187 shift
188 local hooksSlice="${hookName%Hook}Hooks[@]"
190 local hook ret=1
191 # Hack around old bash like above
192 for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do
193 _logHook "$hookName" "$hook" "$@"
194 if _eval "$hook" "$@"; then
195 ret=0
196 break
198 done
200 return "$ret"
204 # Run the named hook, either by calling the function with that name or
205 # by evaluating the variable with that name. This allows convenient
206 # setting of hooks both from Nix expressions (as attributes /
207 # environment variables) and from shell scripts (as functions). If you
208 # want to allow multiple hooks, use runHook instead.
209 _callImplicitHook() {
210 local def="$1"
211 local hookName="$2"
212 if declare -F "$hookName" > /dev/null; then
213 nixTalkativeLog "calling implicit '$hookName' function hook"
214 "$hookName"
215 elif type -p "$hookName" > /dev/null; then
216 nixTalkativeLog "sourcing implicit '$hookName' script hook"
217 source "$hookName"
218 elif [ -n "${!hookName:-}" ]; then
219 nixTalkativeLog "evaling implicit '$hookName' string hook"
220 eval "${!hookName}"
221 else
222 return "$def"
224 # `_eval` expects hook to need nounset disable and leave it
225 # disabled anyways, so Ok to to delegate. The alternative of a
226 # return trap is no good because it would affect nested returns.
230 # A function wrapper around ‘eval’ that ensures that ‘return’ inside
231 # hooks exits the hook, not the caller. Also will only pass args if
232 # command can take them
233 _eval() {
234 if declare -F "$1" > /dev/null 2>&1; then
235 "$@" # including args
236 else
237 eval "$1"
242 ######################################################################
243 # Logging.
245 # Prints a command such that all word splits are unambiguous. We need
246 # to split the command in three parts because the middle format string
247 # will be, and must be, repeated for each argument. The first argument
248 # goes before the ':' and is just for convenience.
249 echoCmd() {
250 printf "%s:" "$1"
251 shift
252 printf ' %q' "$@"
253 echo
257 ######################################################################
258 # Error handling.
260 exitHandler() {
261 exitCode="$?"
262 set +e
264 if [ -n "${showBuildStats:-}" ]; then
265 read -r -d '' -a buildTimes < <(times)
266 echo "build times:"
267 echo "user time for the shell ${buildTimes[0]}"
268 echo "system time for the shell ${buildTimes[1]}"
269 echo "user time for all child processes ${buildTimes[2]}"
270 echo "system time for all child processes ${buildTimes[3]}"
273 if (( "$exitCode" != 0 )); then
274 runHook failureHook
276 # If the builder had a non-zero exit code and
277 # $succeedOnFailure is set, create the file
278 # ‘$out/nix-support/failed’ to signal failure, and exit
279 # normally. Otherwise, return the original exit code.
280 if [ -n "${succeedOnFailure:-}" ]; then
281 echo "build failed with exit code $exitCode (ignored)"
282 mkdir -p "$out/nix-support"
283 printf "%s" "$exitCode" > "$out/nix-support/failed"
284 exit 0
287 else
288 runHook exitHook
291 return "$exitCode"
294 trap "exitHandler" EXIT
297 ######################################################################
298 # Helper functions.
301 addToSearchPathWithCustomDelimiter() {
302 local delimiter="$1"
303 local varName="$2"
304 local dir="$3"
305 if [[ -d "$dir" && "${!varName:+${delimiter}${!varName}${delimiter}}" \
306 != *"${delimiter}${dir}${delimiter}"* ]]; then
307 export "${varName}=${!varName:+${!varName}${delimiter}}${dir}"
311 addToSearchPath() {
312 addToSearchPathWithCustomDelimiter ":" "$@"
315 # Prepend elements to variable "$1", which may come from an attr.
317 # This is useful in generic setup code, which must (for now) support
318 # both derivations with and without __structuredAttrs true, so the
319 # variable may be an array or a space-separated string.
321 # Expressions for individual packages should simply switch to array
322 # syntax when they switch to setting __structuredAttrs = true.
323 prependToVar() {
324 local -n nameref="$1"
325 local useArray type
327 if [ -n "$__structuredAttrs" ]; then
328 useArray=true
329 else
330 useArray=false
333 # check if variable already exist and if it does then do extra checks
334 if type=$(declare -p "$1" 2> /dev/null); then
335 case "${type#* }" in
336 -A*)
337 echo "prependToVar(): ERROR: trying to use prependToVar on an associative array." >&2
338 return 1 ;;
339 -a*)
340 useArray=true ;;
342 useArray=false ;;
343 esac
346 shift
348 if $useArray; then
349 nameref=( "$@" ${nameref+"${nameref[@]}"} )
350 else
351 nameref="$* ${nameref-}"
355 # Same as above
356 appendToVar() {
357 local -n nameref="$1"
358 local useArray type
360 if [ -n "$__structuredAttrs" ]; then
361 useArray=true
362 else
363 useArray=false
366 # check if variable already exist and if it does then do extra checks
367 if type=$(declare -p "$1" 2> /dev/null); then
368 case "${type#* }" in
369 -A*)
370 echo "appendToVar(): ERROR: trying to use appendToVar on an associative array, use variable+=([\"X\"]=\"Y\") instead." >&2
371 return 1 ;;
372 -a*)
373 useArray=true ;;
375 useArray=false ;;
376 esac
379 shift
381 if $useArray; then
382 nameref=( ${nameref+"${nameref[@]}"} "$@" )
383 else
384 nameref="${nameref-} $*"
388 # Accumulate flags from the named variables $2+ into the indexed array $1.
390 # Arrays are simply concatenated, strings are split on whitespace.
391 # Default values can be passed via name=default.
392 concatTo() {
393 local -
394 set -o noglob
395 local -n targetref="$1"; shift
396 local arg default name type
397 for arg in "$@"; do
398 IFS="=" read -r name default <<< "$arg"
399 local -n nameref="$name"
400 if [[ -z "${nameref[*]}" && -n "$default" ]]; then
401 targetref+=( "$default" )
402 elif type=$(declare -p "$name" 2> /dev/null); then
403 case "${type#* }" in
404 -A*)
405 echo "concatTo(): ERROR: trying to use concatTo on an associative array." >&2
406 return 1 ;;
407 -a*)
408 targetref+=( "${nameref[@]}" ) ;;
410 if [[ "$name" = *"Array" ]]; then
411 nixErrorLog "concatTo(): $name is not declared as array, treating as a singleton. This will become an error in future"
412 # Reproduces https://github.com/NixOS/nixpkgs/pull/318614/files#diff-7c7ca80928136cfc73a02d5b28350bd900e331d6d304857053ffc9f7beaad576L359
413 targetref+=( ${nameref+"${nameref[@]}"} )
414 else
415 # shellcheck disable=SC2206
416 targetref+=( ${nameref-} )
419 esac
421 done
424 # Concatenate a list of strings ($2) with a separator ($1) between each element.
425 # The list can be an indexed array of strings or a single string. A single string
426 # is split on spaces and then concatenated with the separator.
428 # $ flags="lorem ipsum dolor sit amet"
429 # $ concatStringsSep ";" flags
430 # lorem;ipsum;dolor;sit;amet
432 # $ flags=("lorem ipsum" "dolor" "sit amet")
433 # $ concatStringsSep ";" flags
434 # lorem ipsum;dolor;sit amet
435 concatStringsSep() {
436 local sep="$1"
437 local name="$2"
438 local type oldifs
439 if type=$(declare -p "$name" 2> /dev/null); then
440 local -n nameref="$name"
441 case "${type#* }" in
442 -A*)
443 echo "concatStringsSep(): ERROR: trying to use concatStringsSep on an associative array." >&2
444 return 1 ;;
445 -a*)
446 local IFS="$sep"
447 echo -n "${nameref[*]}" ;;
449 echo -n "${nameref// /"${sep}"}" ;;
450 esac
454 # Add $1/lib* into rpaths.
455 # The function is used in multiple-outputs.sh hook,
456 # so it is defined here but tried after the hook.
457 _addRpathPrefix() {
458 if [ "${NIX_NO_SELF_RPATH:-0}" != 1 ]; then
459 export NIX_LDFLAGS="-rpath $1/lib ${NIX_LDFLAGS-}"
463 # Return success if the specified file is an ELF object.
464 isELF() {
465 local fn="$1"
466 local fd
467 local magic
468 exec {fd}< "$fn"
469 read -r -n 4 -u "$fd" magic
470 exec {fd}<&-
471 if [ "$magic" = $'\177ELF' ]; then return 0; else return 1; fi
474 # Return success if the specified file is a Mach-O object.
475 isMachO() {
476 local fn="$1"
477 local fd
478 local magic
479 exec {fd}< "$fn"
480 read -r -n 4 -u "$fd" magic
481 exec {fd}<&-
483 # nix uses 'declare -F' in get-env.sh to retrieve the loaded functions.
484 # If we use the $'string' syntax instead of 'echo -ne' then 'declare' will print the raw characters and break nix.
485 # See https://github.com/NixOS/nixpkgs/pull/138334 and https://github.com/NixOS/nix/issues/5262.
487 # https://opensource.apple.com/source/lldb/lldb-310.2.36/examples/python/mach_o.py.auto.html
488 if [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xcf") || "$magic" = $(echo -ne "\xcf\xfa\xed\xfe") ]]; then
489 # MH_MAGIC_64 || MH_CIGAM_64
490 return 0;
491 elif [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xce") || "$magic" = $(echo -ne "\xce\xfa\xed\xfe") ]]; then
492 # MH_MAGIC || MH_CIGAM
493 return 0;
494 elif [[ "$magic" = $(echo -ne "\xca\xfe\xba\xbe") || "$magic" = $(echo -ne "\xbe\xba\xfe\xca") ]]; then
495 # FAT_MAGIC || FAT_CIGAM
496 return 0;
497 else
498 return 1;
502 # Return success if the specified file is a script (i.e. starts with
503 # "#!").
504 isScript() {
505 local fn="$1"
506 local fd
507 local magic
508 exec {fd}< "$fn"
509 read -r -n 2 -u "$fd" magic
510 exec {fd}<&-
511 if [[ "$magic" =~ \#! ]]; then return 0; else return 1; fi
514 # printf unfortunately will print a trailing newline regardless
515 printLines() {
516 (( "$#" > 0 )) || return 0
517 printf '%s\n' "$@"
520 printWords() {
521 (( "$#" > 0 )) || return 0
522 printf '%s ' "$@"
525 ######################################################################
526 # Initialisation.
528 # If using structured attributes, export variables from `env` to the environment.
529 # When not using structured attributes, those variables are already exported.
530 if [[ -n $__structuredAttrs ]]; then
531 for envVar in "${!env[@]}"; do
532 declare -x "${envVar}=${env[${envVar}]}"
533 done
537 # Set a fallback default value for SOURCE_DATE_EPOCH, used by some build tools
538 # to provide a deterministic substitute for the "current" time. Note that
539 # 315532800 = 1980-01-01 12:00:00. We use this date because python's wheel
540 # implementation uses zip archive and zip does not support dates going back to
541 # 1970.
542 export SOURCE_DATE_EPOCH
543 : "${SOURCE_DATE_EPOCH:=315532800}"
546 # Wildcard expansions that don't match should expand to an empty list.
547 # This ensures that, for instance, "for i in *; do ...; done" does the
548 # right thing.
549 shopt -s nullglob
552 # Set up the initial path.
553 PATH=
554 HOST_PATH=
555 for i in $initialPath; do
556 if [ "$i" = / ]; then i=; fi
557 addToSearchPath PATH "$i/bin"
559 # For backward compatibility, we add initial path to HOST_PATH so
560 # it can be used in auto patch-shebangs. Unfortunately this will
561 # not work with cross compilation.
562 if [ -z "${strictDeps-}" ]; then
563 addToSearchPath HOST_PATH "$i/bin"
565 done
567 unset i
569 nixWarnLog "initial path: $PATH"
571 # Check that the pre-hook initialised SHELL.
572 if [ -z "${SHELL:-}" ]; then echo "SHELL not set"; exit 1; fi
573 BASH="$SHELL"
574 export CONFIG_SHELL="$SHELL"
577 # Execute the pre-hook.
578 if [ -z "${shell:-}" ]; then export shell="$SHELL"; fi
579 runHook preHook
582 # Allow the caller to augment buildInputs (it's not always possible to
583 # do this before the call to setup.sh, since the PATH is empty at that
584 # point; here we have a basic Unix environment).
585 runHook addInputsHook
588 # Package accumulators
590 declare -a pkgsBuildBuild pkgsBuildHost pkgsBuildTarget
591 declare -a pkgsHostHost pkgsHostTarget
592 declare -a pkgsTargetTarget
594 declare -a pkgBuildAccumVars=(pkgsBuildBuild pkgsBuildHost pkgsBuildTarget)
595 declare -a pkgHostAccumVars=(pkgsHostHost pkgsHostTarget)
596 declare -a pkgTargetAccumVars=(pkgsTargetTarget)
598 declare -a pkgAccumVarVars=(pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars)
601 # Hooks
603 declare -a envBuildBuildHooks envBuildHostHooks envBuildTargetHooks
604 declare -a envHostHostHooks envHostTargetHooks
605 declare -a envTargetTargetHooks
607 declare -a pkgBuildHookVars=(envBuildBuildHook envBuildHostHook envBuildTargetHook)
608 declare -a pkgHostHookVars=(envHostHostHook envHostTargetHook)
609 declare -a pkgTargetHookVars=(envTargetTargetHook)
611 declare -a pkgHookVarVars=(pkgBuildHookVars pkgHostHookVars pkgTargetHookVars)
613 # those variables are declared here, since where and if they are used varies
614 declare -a preFixupHooks fixupOutputHooks preConfigureHooks postFixupHooks postUnpackHooks unpackCmdHooks
616 # Add env hooks for all sorts of deps with the specified host offset.
617 addEnvHooks() {
618 local depHostOffset="$1"
619 shift
620 local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]"
621 local pkgHookVar
622 for pkgHookVar in "${!pkgHookVarsSlice}"; do
623 eval "${pkgHookVar}s"'+=("$@")'
624 done
628 # Propagated dep files
630 declare -a propagatedBuildDepFiles=(
631 propagated-build-build-deps
632 propagated-native-build-inputs # Legacy name for back-compat
633 propagated-build-target-deps
635 declare -a propagatedHostDepFiles=(
636 propagated-host-host-deps
637 propagated-build-inputs # Legacy name for back-compat
639 declare -a propagatedTargetDepFiles=(
640 propagated-target-target-deps
642 declare -a propagatedDepFilesVars=(
643 propagatedBuildDepFiles
644 propagatedHostDepFiles
645 propagatedTargetDepFiles
648 # Platform offsets: build = -1, host = 0, target = 1
649 declare -a allPlatOffsets=(-1 0 1)
652 # Mutually-recursively find all build inputs. See the dependency section of the
653 # stdenv chapter of the Nixpkgs manual for the specification this algorithm
654 # implements.
655 findInputs() {
656 local -r pkg="$1"
657 local -r hostOffset="$2"
658 local -r targetOffset="$3"
660 # Sanity check
661 (( hostOffset <= targetOffset )) || exit 1
663 # shellcheck disable=SC1087
664 local varVar="${pkgAccumVarVars[hostOffset + 1]}"
665 # shellcheck disable=SC1087
666 local varRef="$varVar[$((targetOffset - hostOffset))]"
667 local var="${!varRef}"
668 unset -v varVar varRef
670 # TODO(@Ericson2314): Restore using associative array once Darwin
671 # nix-shell doesn't use impure bash. This should replace the O(n)
672 # case with an O(1) hash map lookup, assuming bash is implemented
673 # well :D.
674 # shellcheck disable=SC1087
675 local varSlice="$var[*]"
676 # ${..-} to hack around old bash empty array problem
677 case "${!varSlice-}" in
678 *" $pkg "*) return 0 ;;
679 esac
680 unset -v varSlice
682 eval "$var"'+=("$pkg")'
684 if ! [ -e "$pkg" ]; then
685 echo "build input $pkg does not exist" >&2
686 exit 1
689 # The current package's host and target offset together
690 # provide a <=-preserving homomorphism from the relative
691 # offsets to current offset
692 function mapOffset() {
693 local -r inputOffset="$1"
694 local -n outputOffset="$2"
695 if (( inputOffset <= 0 )); then
696 outputOffset=$((inputOffset + hostOffset))
697 else
698 outputOffset=$((inputOffset - 1 + targetOffset))
702 # Host offset relative to that of the package whose immediate
703 # dependencies we are currently exploring.
704 local relHostOffset
705 for relHostOffset in "${allPlatOffsets[@]}"; do
706 # `+ 1` so we start at 0 for valid index
707 local files="${propagatedDepFilesVars[relHostOffset + 1]}"
709 # Host offset relative to the package currently being
710 # built---as absolute an offset as will be used.
711 local hostOffsetNext
712 mapOffset "$relHostOffset" hostOffsetNext
714 # Ensure we're in bounds relative to the package currently
715 # being built.
716 (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue
718 # Target offset relative to the *host* offset of the package
719 # whose immediate dependencies we are currently exploring.
720 local relTargetOffset
721 for relTargetOffset in "${allPlatOffsets[@]}"; do
722 (( "$relHostOffset" <= "$relTargetOffset" )) || continue
724 local fileRef="${files}[$relTargetOffset - $relHostOffset]"
725 local file="${!fileRef}"
726 unset -v fileRef
728 # Target offset relative to the package currently being
729 # built.
730 local targetOffsetNext
731 mapOffset "$relTargetOffset" targetOffsetNext
733 # Once again, ensure we're in bounds relative to the
734 # package currently being built.
735 (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue
737 [[ -f "$pkg/nix-support/$file" ]] || continue
739 local pkgNext
740 read -r -d '' pkgNext < "$pkg/nix-support/$file" || true
741 for pkgNext in $pkgNext; do
742 findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext"
743 done
744 done
745 done
748 # The way we handle deps* and *Inputs works with structured attrs
749 # either enabled or disabled. For this it's convenient that the items
750 # in each list must be store paths, and therefore space-free.
752 # Make sure all are at least defined as empty
753 : "${depsBuildBuild=}" "${depsBuildBuildPropagated=}"
754 : "${nativeBuildInputs=}" "${propagatedNativeBuildInputs=}" "${defaultNativeBuildInputs=}"
755 : "${depsBuildTarget=}" "${depsBuildTargetPropagated=}"
756 : "${depsHostHost=}" "${depsHostHostPropagated=}"
757 : "${buildInputs=}" "${propagatedBuildInputs=}" "${defaultBuildInputs=}"
758 : "${depsTargetTarget=}" "${depsTargetTargetPropagated=}"
760 for pkg in ${depsBuildBuild[@]} ${depsBuildBuildPropagated[@]}; do
761 findInputs "$pkg" -1 -1
762 done
763 for pkg in ${nativeBuildInputs[@]} ${propagatedNativeBuildInputs[@]}; do
764 findInputs "$pkg" -1 0
765 done
766 for pkg in ${depsBuildTarget[@]} ${depsBuildTargetPropagated[@]}; do
767 findInputs "$pkg" -1 1
768 done
769 for pkg in ${depsHostHost[@]} ${depsHostHostPropagated[@]}; do
770 findInputs "$pkg" 0 0
771 done
772 for pkg in ${buildInputs[@]} ${propagatedBuildInputs[@]} ; do
773 findInputs "$pkg" 0 1
774 done
775 for pkg in ${depsTargetTarget[@]} ${depsTargetTargetPropagated[@]}; do
776 findInputs "$pkg" 1 1
777 done
778 # Default inputs must be processed last
779 for pkg in ${defaultNativeBuildInputs[@]}; do
780 findInputs "$pkg" -1 0
781 done
782 for pkg in ${defaultBuildInputs[@]}; do
783 findInputs "$pkg" 0 1
784 done
786 # Add package to the future PATH and run setup hooks
787 activatePackage() {
788 local pkg="$1"
789 local -r hostOffset="$2"
790 local -r targetOffset="$3"
792 # Sanity check
793 (( hostOffset <= targetOffset )) || exit 1
795 if [ -f "$pkg" ]; then
796 nixTalkativeLog "sourcing setup hook '$pkg'"
797 source "$pkg"
800 # Only dependencies whose host platform is guaranteed to match the
801 # build platform are included here. That would be `depsBuild*`,
802 # and legacy `nativeBuildInputs`, in general. If we aren't cross
803 # compiling, however, everything can be put on the PATH. To ease
804 # the transition, we do include everything in that case.
806 # TODO(@Ericson2314): Don't special-case native compilation
807 if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then
808 addToSearchPath _PATH "$pkg/bin"
811 if (( hostOffset <= -1 )); then
812 addToSearchPath _XDG_DATA_DIRS "$pkg/share"
815 if [[ "$hostOffset" -eq 0 && -d "$pkg/bin" ]]; then
816 addToSearchPath _HOST_PATH "$pkg/bin"
819 if [[ -f "$pkg/nix-support/setup-hook" ]]; then
820 nixTalkativeLog "sourcing setup hook '$pkg/nix-support/setup-hook'"
821 source "$pkg/nix-support/setup-hook"
825 _activatePkgs() {
826 local hostOffset targetOffset
827 local pkg
829 for hostOffset in "${allPlatOffsets[@]}"; do
830 local pkgsVar="${pkgAccumVarVars[hostOffset + 1]}"
831 for targetOffset in "${allPlatOffsets[@]}"; do
832 (( hostOffset <= targetOffset )) || continue
833 local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]"
834 local pkgsSlice="${!pkgsRef}[@]"
835 for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do
836 activatePackage "$pkg" "$hostOffset" "$targetOffset"
837 done
838 done
839 done
842 # Run the package setup hooks and build _PATH
843 _activatePkgs
845 # Set the relevant environment variables to point to the build inputs
846 # found above.
848 # These `depOffset`s, beyond indexing the arrays, also tell the env
849 # hook what sort of dependency (ignoring propagatedness) is being
850 # passed to the env hook. In a real language, we'd append a closure
851 # with this information to the relevant env hook array, but bash
852 # doesn't have closures, so it's easier to just pass this in.
853 _addToEnv() {
854 local depHostOffset depTargetOffset
855 local pkg
857 for depHostOffset in "${allPlatOffsets[@]}"; do
858 local hookVar="${pkgHookVarVars[depHostOffset + 1]}"
859 local pkgsVar="${pkgAccumVarVars[depHostOffset + 1]}"
860 for depTargetOffset in "${allPlatOffsets[@]}"; do
861 (( depHostOffset <= depTargetOffset )) || continue
862 local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]"
863 if [[ -z "${strictDeps-}" ]]; then
865 # Keep track of which packages we have visited before.
866 local visitedPkgs=""
868 # Apply environment hooks to all packages during native
869 # compilation to ease the transition.
871 # TODO(@Ericson2314): Don't special-case native compilation
872 for pkg in \
873 "${pkgsBuildBuild[@]}" \
874 "${pkgsBuildHost[@]}" \
875 "${pkgsBuildTarget[@]}" \
876 "${pkgsHostHost[@]}" \
877 "${pkgsHostTarget[@]}" \
878 "${pkgsTargetTarget[@]}"
880 if [[ "$visitedPkgs" = *"$pkg"* ]]; then
881 continue
883 runHook "${!hookRef}" "$pkg"
884 visitedPkgs+=" $pkg"
885 done
886 else
887 local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]"
888 local pkgsSlice="${!pkgsRef}[@]"
889 for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do
890 runHook "${!hookRef}" "$pkg"
891 done
893 done
894 done
897 # Run the package-specific hooks set by the setup-hook scripts.
898 _addToEnv
901 # Unset setup-specific declared variables
902 unset allPlatOffsets
903 unset pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars pkgAccumVarVars
904 unset pkgBuildHookVars pkgHostHookVars pkgTargetHookVars pkgHookVarVars
905 unset propagatedDepFilesVars
908 _addRpathPrefix "$out"
911 # Set the TZ (timezone) environment variable, otherwise commands like
912 # `date' will complain (e.g., `Tue Mar 9 10:01:47 Local time zone must
913 # be set--see zic manual page 2004').
914 export TZ=UTC
917 # Set the prefix. This is generally $out, but it can be overriden,
918 # for instance if we just want to perform a test build/install to a
919 # temporary location and write a build report to $out.
920 if [ -z "${prefix:-}" ]; then
921 prefix="$out";
924 if [ "${useTempPrefix:-}" = 1 ]; then
925 prefix="$NIX_BUILD_TOP/tmp_prefix";
929 PATH="${_PATH-}${_PATH:+${PATH:+:}}$PATH"
930 HOST_PATH="${_HOST_PATH-}${_HOST_PATH:+${HOST_PATH:+:}}$HOST_PATH"
931 export XDG_DATA_DIRS="${_XDG_DATA_DIRS-}${_XDG_DATA_DIRS:+${XDG_DATA_DIRS:+:}}${XDG_DATA_DIRS-}"
933 nixWarnLog "final path: $PATH"
934 nixWarnLog "final host path: $HOST_PATH"
935 nixWarnLog "final data dirs: $XDG_DATA_DIRS"
937 unset _PATH
938 unset _HOST_PATH
939 unset _XDG_DATA_DIRS
942 # Normalize the NIX_BUILD_CORES variable. The value might be 0, which
943 # means that we're supposed to try and auto-detect the number of
944 # available CPU cores at run-time.
946 NIX_BUILD_CORES="${NIX_BUILD_CORES:-1}"
947 if ((NIX_BUILD_CORES <= 0)); then
948 guess=$(nproc 2>/dev/null || true)
949 ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess))
951 export NIX_BUILD_CORES
954 # Prevent SSL libraries from using certificates in /etc/ssl, unless set explicitly.
955 # Leave it in impure shells for convenience.
956 if [[ -z "${NIX_SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]; then
957 export NIX_SSL_CERT_FILE=/no-cert-file.crt
959 # Another variant left for compatibility.
960 if [[ -z "${SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]; then
961 export SSL_CERT_FILE=/no-cert-file.crt
965 ######################################################################
966 # Textual substitution functions.
968 # only log once, due to max logging limit on hydra
969 _substituteStream_has_warned_replace_deprecation=false
971 substituteStream() {
972 local var=$1
973 local description=$2
974 shift 2
976 while (( "$#" )); do
977 local replace_mode="$1"
978 case "$1" in
979 --replace)
980 # deprecated 2023-11-22
981 # this will either get removed, or switch to the behaviour of --replace-fail in the future
982 if ! "$_substituteStream_has_warned_replace_deprecation"; then
983 echo "substituteStream() in derivation $name: WARNING: '--replace' is deprecated, use --replace-{fail,warn,quiet}. ($description)" >&2
984 _substituteStream_has_warned_replace_deprecation=true
986 replace_mode='--replace-warn'
988 --replace-quiet|--replace-warn|--replace-fail)
989 pattern="$2"
990 replacement="$3"
991 shift 3
992 local savedvar
993 savedvar="${!var}"
994 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
995 if [ "$pattern" != "$replacement" ]; then
996 if [ "${!var}" == "$savedvar" ]; then
997 if [ "$replace_mode" == --replace-warn ]; then
998 printf "substituteStream() in derivation $name: WARNING: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2
999 elif [ "$replace_mode" == --replace-fail ]; then
1000 printf "substituteStream() in derivation $name: ERROR: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2
1001 return 1
1007 --subst-var)
1008 local varName="$2"
1009 shift 2
1010 # check if the used nix attribute name is a valid bash name
1011 if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
1012 echo "substituteStream() in derivation $name: ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2
1013 return 1
1015 if [ -z ${!varName+x} ]; then
1016 echo "substituteStream() in derivation $name: ERROR: variable \$$varName is unset" >&2
1017 return 1
1019 pattern="@$varName@"
1020 replacement="${!varName}"
1021 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
1024 --subst-var-by)
1025 pattern="@$2@"
1026 replacement="$3"
1027 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
1028 shift 3
1032 echo "substituteStream() in derivation $name: ERROR: Invalid command line argument: $1" >&2
1033 return 1
1035 esac
1036 done
1038 printf "%s" "${!var}"
1041 # put the content of a file in a variable
1042 # fail loudly if provided with a binary (containing null bytes)
1043 consumeEntire() {
1044 # read returns non-0 on EOF, so we want read to fail
1045 if IFS='' read -r -d '' "$1" ; then
1046 echo "consumeEntire(): ERROR: Input null bytes, won't process" >&2
1047 return 1
1051 substitute() {
1052 local input="$1"
1053 local output="$2"
1054 shift 2
1056 if [ ! -f "$input" ]; then
1057 echo "substitute(): ERROR: file '$input' does not exist" >&2
1058 return 1
1061 local content
1062 consumeEntire content < "$input"
1064 if [ -e "$output" ]; then chmod +w "$output"; fi
1065 substituteStream content "file '$input'" "$@" > "$output"
1068 substituteInPlace() {
1069 local -a fileNames=()
1070 for arg in "$@"; do
1071 if [[ "$arg" = "--"* ]]; then
1072 break
1074 fileNames+=("$arg")
1075 shift
1076 done
1077 if ! [[ "${#fileNames[@]}" -gt 0 ]]; then
1078 echo >&2 "substituteInPlace called without any files to operate on (files must come before options!)"
1079 return 1
1082 for file in "${fileNames[@]}"; do
1083 substitute "$file" "$file" "$@"
1084 done
1087 _allFlags() {
1088 # Export some local variables for the `awk` below so some substitutions (such as name)
1089 # don't have to be in the env attrset when `__structuredAttrs` is enabled.
1090 export system pname name version
1091 while IFS='' read -r varName; do
1092 nixTalkativeLog "@${varName}@ -> ${!varName}"
1093 args+=("--subst-var" "$varName")
1094 done < <(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }')
1097 substituteAllStream() {
1098 local -a args=()
1099 _allFlags
1101 substituteStream "$1" "$2" "${args[@]}"
1104 # Substitute all environment variables that start with a lowercase character and
1105 # are valid Bash names.
1106 substituteAll() {
1107 local input="$1"
1108 local output="$2"
1110 local -a args=()
1111 _allFlags
1113 substitute "$input" "$output" "${args[@]}"
1117 substituteAllInPlace() {
1118 local fileName="$1"
1119 shift
1120 substituteAll "$fileName" "$fileName" "$@"
1124 ######################################################################
1125 # What follows is the generic builder.
1128 # This function is useful for debugging broken Nix builds. It dumps
1129 # all environment variables to a file `env-vars' in the build
1130 # directory. If the build fails and the `-K' option is used, you can
1131 # then go to the build directory and source in `env-vars' to reproduce
1132 # the environment used for building.
1133 dumpVars() {
1134 if [ "${noDumpEnvVars:-0}" != 1 ]; then
1135 # On darwin, install(1) cannot be called with /dev/stdin or fd from process substitution
1136 # so first we create the file and then write to it
1137 # See https://github.com/NixOS/nixpkgs/issues/335016
1139 install -m 0600 /dev/null "$NIX_BUILD_TOP/env-vars" &&
1140 export 2>/dev/null >| "$NIX_BUILD_TOP/env-vars"
1141 } || true
1146 # Utility function: echo the base name of the given path, with the
1147 # prefix `HASH-' removed, if present.
1148 stripHash() {
1149 local strippedName casematchOpt=0
1150 # On separate line for `set -e`
1151 strippedName="$(basename -- "$1")"
1152 shopt -q nocasematch && casematchOpt=1
1153 shopt -u nocasematch
1154 if [[ "$strippedName" =~ ^[a-z0-9]{32}- ]]; then
1155 echo "${strippedName:33}"
1156 else
1157 echo "$strippedName"
1159 if (( casematchOpt )); then shopt -s nocasematch; fi
1163 recordPropagatedDependencies() {
1164 # Propagate dependencies into the development output.
1165 declare -ra flatVars=(
1166 # Build
1167 depsBuildBuildPropagated
1168 propagatedNativeBuildInputs
1169 depsBuildTargetPropagated
1170 # Host
1171 depsHostHostPropagated
1172 propagatedBuildInputs
1173 # Target
1174 depsTargetTargetPropagated
1176 declare -ra flatFiles=(
1177 "${propagatedBuildDepFiles[@]}"
1178 "${propagatedHostDepFiles[@]}"
1179 "${propagatedTargetDepFiles[@]}"
1182 local propagatedInputsIndex
1183 for propagatedInputsIndex in "${!flatVars[@]}"; do
1184 local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]"
1185 local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}"
1187 [[ "${!propagatedInputsSlice}" ]] || continue
1189 mkdir -p "${!outputDev}/nix-support"
1190 # shellcheck disable=SC2086
1191 printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile"
1192 done
1196 unpackCmdHooks+=(_defaultUnpack)
1197 _defaultUnpack() {
1198 local fn="$1"
1199 local destination
1201 if [ -d "$fn" ]; then
1203 destination="$(stripHash "$fn")"
1205 if [ -e "$destination" ]; then
1206 echo "Cannot copy $fn to $destination: destination already exists!"
1207 echo "Did you specify two \"srcs\" with the same \"name\"?"
1208 return 1
1211 # We can't preserve hardlinks because they may have been
1212 # introduced by store optimization, which might break things
1213 # in the build.
1214 cp -pr --reflink=auto -- "$fn" "$destination"
1216 else
1218 case "$fn" in
1219 *.tar.xz | *.tar.lzma | *.txz)
1220 # Don't rely on tar knowing about .xz.
1221 # Additionally, we have multiple different xz binaries with different feature sets in different
1222 # stages. The XZ_OPT env var is only used by the full "XZ utils" implementation, which supports
1223 # the --threads (-T) flag. This allows us to enable multithreaded decompression exclusively on
1224 # that implementation, without the use of complex bash conditionals and checks.
1225 # Since tar does not control the decompression, we need to
1226 # disregard the error code from the xz invocation. Otherwise,
1227 # it can happen that tar exits earlier, causing xz to fail
1228 # from a SIGPIPE.
1229 (XZ_OPT="--threads=$NIX_BUILD_CORES" xz -d < "$fn"; true) | tar xf - --mode=+w --warning=no-timestamp
1231 *.tar | *.tar.* | *.tgz | *.tbz2 | *.tbz)
1232 # GNU tar can automatically select the decompression method
1233 # (info "(tar) gzip").
1234 tar xf "$fn" --mode=+w --warning=no-timestamp
1237 return 1
1239 esac
1245 unpackFile() {
1246 curSrc="$1"
1247 echo "unpacking source archive $curSrc"
1248 if ! runOneHook unpackCmd "$curSrc"; then
1249 echo "do not know how to unpack source archive $curSrc"
1250 exit 1
1255 unpackPhase() {
1256 runHook preUnpack
1258 if [ -z "${srcs:-}" ]; then
1259 if [ -z "${src:-}" ]; then
1260 # shellcheck disable=SC2016
1261 echo 'variable $src or $srcs should point to the source'
1262 exit 1
1264 srcs="$src"
1267 local -a srcsArray
1268 concatTo srcsArray srcs
1270 # To determine the source directory created by unpacking the
1271 # source archives, we record the contents of the current
1272 # directory, then look below which directory got added. Yeah,
1273 # it's rather hacky.
1274 local dirsBefore=""
1275 for i in *; do
1276 if [ -d "$i" ]; then
1277 dirsBefore="$dirsBefore $i "
1279 done
1281 # Unpack all source archives.
1282 for i in "${srcsArray[@]}"; do
1283 unpackFile "$i"
1284 done
1286 # Find the source directory.
1288 # set to empty if unset
1289 : "${sourceRoot=}"
1291 if [ -n "${setSourceRoot:-}" ]; then
1292 runOneHook setSourceRoot
1293 elif [ -z "$sourceRoot" ]; then
1294 for i in *; do
1295 if [ -d "$i" ]; then
1296 case $dirsBefore in
1297 *\ $i\ *)
1300 if [ -n "$sourceRoot" ]; then
1301 echo "unpacker produced multiple directories"
1302 exit 1
1304 sourceRoot="$i"
1306 esac
1308 done
1311 if [ -z "$sourceRoot" ]; then
1312 echo "unpacker appears to have produced no directories"
1313 exit 1
1316 echo "source root is $sourceRoot"
1318 # By default, add write permission to the sources. This is often
1319 # necessary when sources have been copied from other store
1320 # locations.
1321 if [ "${dontMakeSourcesWritable:-0}" != 1 ]; then
1322 chmod -R u+w -- "$sourceRoot"
1325 runHook postUnpack
1329 patchPhase() {
1330 runHook prePatch
1332 local -a patchesArray
1333 concatTo patchesArray patches
1335 for i in "${patchesArray[@]}"; do
1336 echo "applying patch $i"
1337 local uncompress=cat
1338 case "$i" in
1339 *.gz)
1340 uncompress="gzip -d"
1342 *.bz2)
1343 uncompress="bzip2 -d"
1345 *.xz)
1346 uncompress="xz -d"
1348 *.lzma)
1349 uncompress="lzma -d"
1351 esac
1353 local -a flagsArray
1354 concatTo flagsArray patchFlags=-p1
1355 # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.)
1356 # shellcheck disable=SC2086
1357 $uncompress < "$i" 2>&1 | patch "${flagsArray[@]}"
1358 done
1360 runHook postPatch
1364 fixLibtool() {
1365 local search_path
1366 for flag in $NIX_LDFLAGS; do
1367 case $flag in
1368 -L*)
1369 search_path+=" ${flag#-L}"
1371 esac
1372 done
1374 sed -i "$1" \
1375 -e "s^eval \(sys_lib_search_path=\).*^\1'${search_path:-}'^" \
1376 -e 's^eval sys_lib_.+search_path=.*^^'
1380 configurePhase() {
1381 runHook preConfigure
1383 # set to empty if unset
1384 : "${configureScript=}"
1386 if [[ -z "$configureScript" && -x ./configure ]]; then
1387 configureScript=./configure
1390 if [ -z "${dontFixLibtool:-}" ]; then
1391 export lt_cv_deplibs_check_method="${lt_cv_deplibs_check_method-pass_all}"
1392 local i
1393 find . -iname "ltmain.sh" -print0 | while IFS='' read -r -d '' i; do
1394 echo "fixing libtool script $i"
1395 fixLibtool "$i"
1396 done
1398 # replace `/usr/bin/file` with `file` in any `configure`
1399 # scripts with vendored libtool code. Preserve mtimes to
1400 # prevent some packages (e.g. libidn2) from spontaneously
1401 # autoreconf'ing themselves
1402 CONFIGURE_MTIME_REFERENCE=$(mktemp configure.mtime.reference.XXXXXX)
1403 find . \
1404 -executable \
1405 -type f \
1406 -name configure \
1407 -exec grep -l 'GNU Libtool is free software; you can redistribute it and/or modify' {} \; \
1408 -exec touch -r {} "$CONFIGURE_MTIME_REFERENCE" \; \
1409 -exec sed -i s_/usr/bin/file_file_g {} \; \
1410 -exec touch -r "$CONFIGURE_MTIME_REFERENCE" {} \;
1411 rm -f "$CONFIGURE_MTIME_REFERENCE"
1414 if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then
1415 prependToVar configureFlags "${prefixKey:---prefix=}$prefix"
1418 if [[ -f "$configureScript" ]]; then
1419 # Add --disable-dependency-tracking to speed up some builds.
1420 if [ -z "${dontAddDisableDepTrack:-}" ]; then
1421 if grep -q dependency-tracking "$configureScript"; then
1422 prependToVar configureFlags --disable-dependency-tracking
1426 # By default, disable static builds.
1427 if [ -z "${dontDisableStatic:-}" ]; then
1428 if grep -q enable-static "$configureScript"; then
1429 prependToVar configureFlags --disable-static
1433 if [ -z "${dontPatchShebangsInConfigure:-}" ]; then
1434 patchShebangs --build "$configureScript"
1438 if [ -n "$configureScript" ]; then
1439 local -a flagsArray
1440 concatTo flagsArray configureFlags configureFlagsArray
1442 echoCmd 'configure flags' "${flagsArray[@]}"
1443 # shellcheck disable=SC2086
1444 $configureScript "${flagsArray[@]}"
1445 unset flagsArray
1446 else
1447 echo "no configure script, doing nothing"
1450 runHook postConfigure
1454 buildPhase() {
1455 runHook preBuild
1457 if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then
1458 echo "no Makefile or custom buildPhase, doing nothing"
1459 else
1460 foundMakefile=1
1462 # shellcheck disable=SC2086
1463 local flagsArray=(
1464 ${enableParallelBuilding:+-j${NIX_BUILD_CORES}}
1465 SHELL="$SHELL"
1467 concatTo flagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray
1469 echoCmd 'build flags' "${flagsArray[@]}"
1470 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1471 unset flagsArray
1474 runHook postBuild
1478 checkPhase() {
1479 runHook preCheck
1481 if [[ -z "${foundMakefile:-}" ]]; then
1482 echo "no Makefile or custom checkPhase, doing nothing"
1483 runHook postCheck
1484 return
1487 if [[ -z "${checkTarget:-}" ]]; then
1488 #TODO(@oxij): should flagsArray influence make -n?
1489 if make -n ${makefile:+-f $makefile} check >/dev/null 2>&1; then
1490 checkTarget="check"
1491 elif make -n ${makefile:+-f $makefile} test >/dev/null 2>&1; then
1492 checkTarget="test"
1496 if [[ -z "${checkTarget:-}" ]]; then
1497 echo "no check/test target in ${makefile:-Makefile}, doing nothing"
1498 else
1499 # Old bash empty array hack
1500 # shellcheck disable=SC2086
1501 local flagsArray=(
1502 ${enableParallelChecking:+-j${NIX_BUILD_CORES}}
1503 SHELL="$SHELL"
1506 concatTo flagsArray makeFlags makeFlagsArray checkFlags=VERBOSE=y checkFlagsArray checkTarget
1508 echoCmd 'check flags' "${flagsArray[@]}"
1509 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1511 unset flagsArray
1514 runHook postCheck
1518 installPhase() {
1519 runHook preInstall
1521 # Dont reuse 'foundMakefile' set in buildPhase, a makefile may have been created in buildPhase
1522 if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then
1523 echo "no Makefile or custom installPhase, doing nothing"
1524 runHook postInstall
1525 return
1526 else
1527 foundMakefile=1
1530 if [ -n "$prefix" ]; then
1531 mkdir -p "$prefix"
1534 # shellcheck disable=SC2086
1535 local flagsArray=(
1536 ${enableParallelInstalling:+-j${NIX_BUILD_CORES}}
1537 SHELL="$SHELL"
1540 concatTo flagsArray makeFlags makeFlagsArray installFlags installFlagsArray installTargets=install
1542 echoCmd 'install flags' "${flagsArray[@]}"
1543 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1544 unset flagsArray
1546 runHook postInstall
1550 # The fixup phase performs generic, package-independent stuff, like
1551 # stripping binaries, running patchelf and setting
1552 # propagated-build-inputs.
1553 fixupPhase() {
1554 # Make sure everything is writable so "strip" et al. work.
1555 local output
1556 for output in $(getAllOutputNames); do
1557 # for set*id bits see #300635
1558 if [ -e "${!output}" ]; then chmod -R u+w,u-s,g-s "${!output}"; fi
1559 done
1561 runHook preFixup
1563 # Apply fixup to each output.
1564 local output
1565 for output in $(getAllOutputNames); do
1566 prefix="${!output}" runHook fixupOutput
1567 done
1570 # record propagated dependencies & setup hook into the development output.
1571 recordPropagatedDependencies
1573 if [ -n "${setupHook:-}" ]; then
1574 mkdir -p "${!outputDev}/nix-support"
1575 substituteAll "$setupHook" "${!outputDev}/nix-support/setup-hook"
1578 # TODO(@Ericson2314): Remove after https://github.com/NixOS/nixpkgs/pull/31414
1579 if [ -n "${setupHooks:-}" ]; then
1580 mkdir -p "${!outputDev}/nix-support"
1581 local hook
1582 # have to use ${setupHooks[@]} without quotes because it needs to support setupHooks being a array or a whitespace separated string
1583 # # values of setupHooks won't have spaces so it won't cause problems
1584 # shellcheck disable=2068
1585 for hook in ${setupHooks[@]}; do
1586 local content
1587 consumeEntire content < "$hook"
1588 substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook"
1589 unset -v content
1590 done
1591 unset -v hook
1594 # Propagate user-env packages into the output with binaries, TODO?
1596 if [ -n "${propagatedUserEnvPkgs:-}" ]; then
1597 mkdir -p "${!outputBin}/nix-support"
1598 # shellcheck disable=SC2086
1599 printWords $propagatedUserEnvPkgs > "${!outputBin}/nix-support/propagated-user-env-packages"
1602 runHook postFixup
1606 installCheckPhase() {
1607 runHook preInstallCheck
1609 if [[ -z "${foundMakefile:-}" ]]; then
1610 echo "no Makefile or custom installCheckPhase, doing nothing"
1611 #TODO(@oxij): should flagsArray influence make -n?
1612 elif [[ -z "${installCheckTarget:-}" ]] \
1613 && ! make -n ${makefile:+-f $makefile} "${installCheckTarget:-installcheck}" >/dev/null 2>&1; then
1614 echo "no installcheck target in ${makefile:-Makefile}, doing nothing"
1615 else
1616 # Old bash empty array hack
1617 # shellcheck disable=SC2086
1618 local flagsArray=(
1619 ${enableParallelChecking:+-j${NIX_BUILD_CORES}}
1620 SHELL="$SHELL"
1623 concatTo flagsArray makeFlags makeFlagsArray \
1624 installCheckFlags installCheckFlagsArray installCheckTarget=installcheck
1626 echoCmd 'installcheck flags' "${flagsArray[@]}"
1627 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1628 unset flagsArray
1631 runHook postInstallCheck
1635 distPhase() {
1636 runHook preDist
1638 local flagsArray=()
1639 concatTo flagsArray distFlags distFlagsArray distTarget=dist
1641 echo 'dist flags: %q' "${flagsArray[@]}"
1642 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1644 if [ "${dontCopyDist:-0}" != 1 ]; then
1645 mkdir -p "$out/tarballs"
1647 # Note: don't quote $tarballs, since we explicitly permit
1648 # wildcards in there.
1649 # shellcheck disable=SC2086
1650 cp -pvd ${tarballs[*]:-*.tar.gz} "$out/tarballs"
1653 runHook postDist
1657 showPhaseHeader() {
1658 local phase="$1"
1659 echo "Running phase: $phase"
1661 # The Nix structured logger allows derivations to update the phase as they're building,
1662 # which shows up in the terminal UI. See `handleJSONLogMessage` in the Nix source.
1663 if [[ -z ${NIX_LOG_FD-} ]]; then
1664 return
1666 printf "@nix { \"action\": \"setPhase\", \"phase\": \"%s\" }\n" "$phase" >&"$NIX_LOG_FD"
1670 showPhaseFooter() {
1671 local phase="$1"
1672 local startTime="$2"
1673 local endTime="$3"
1674 local delta=$(( endTime - startTime ))
1675 (( delta < 30 )) && return
1677 local H=$((delta/3600))
1678 local M=$((delta%3600/60))
1679 local S=$((delta%60))
1680 echo -n "$phase completed in "
1681 (( H > 0 )) && echo -n "$H hours "
1682 (( M > 0 )) && echo -n "$M minutes "
1683 echo "$S seconds"
1687 runPhase() {
1688 local curPhase="$*"
1689 if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then return; fi
1690 if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then return; fi
1691 if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then return; fi
1692 if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then return; fi
1693 if [[ "$curPhase" = checkPhase && -z "${doCheck:-}" ]]; then return; fi
1694 if [[ "$curPhase" = installPhase && -n "${dontInstall:-}" ]]; then return; fi
1695 if [[ "$curPhase" = fixupPhase && -n "${dontFixup:-}" ]]; then return; fi
1696 if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then return; fi
1697 if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then return; fi
1699 showPhaseHeader "$curPhase"
1700 dumpVars
1702 local startTime endTime
1703 startTime=$(date +"%s")
1705 # Evaluate the variable named $curPhase if it exists, otherwise the
1706 # function named $curPhase.
1707 eval "${!curPhase:-$curPhase}"
1709 endTime=$(date +"%s")
1711 showPhaseFooter "$curPhase" "$startTime" "$endTime"
1713 if [ "$curPhase" = unpackPhase ]; then
1714 # make sure we can cd into the directory
1715 [ -n "${sourceRoot:-}" ] && chmod +x -- "${sourceRoot}"
1717 cd -- "${sourceRoot:-.}"
1722 genericBuild() {
1723 # variable used by our gzip wrapper to add -n.
1724 # gzip is in common-path.nix and is added to nix-shell but we only want to change its behaviour in nix builds. do not move to a setupHook in gzip.
1725 export GZIP_NO_TIMESTAMPS=1
1727 if [ -f "${buildCommandPath:-}" ]; then
1728 source "$buildCommandPath"
1729 return
1731 if [ -n "${buildCommand:-}" ]; then
1732 eval "$buildCommand"
1733 return
1736 if [ -z "${phases[*]:-}" ]; then
1737 phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} \
1738 configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase \
1739 ${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase \
1740 ${preDistPhases[*]:-} distPhase ${postPhases[*]:-}";
1743 # The use of ${phases[*]} gives the correct behavior both with and
1744 # without structured attrs. This relies on the fact that each
1745 # phase name is space-free, which it must be because it's the name
1746 # of either a shell variable or a shell function.
1747 for curPhase in ${phases[*]}; do
1748 runPhase "$curPhase"
1749 done
1753 # Execute the post-hooks.
1754 runHook postHook
1757 # Execute the global user hook (defined through the Nixpkgs
1758 # configuration option ‘stdenv.userHook’). This can be used to set
1759 # global compiler optimisation flags, for instance.
1760 runHook userHook
1763 dumpVars
1766 # Restore the original options for nix-shell
1767 [[ $__nixpkgs_setup_set_original == *e* ]] || set +e
1768 [[ $__nixpkgs_setup_set_original == *u* ]] || set +u
1769 unset -v __nixpkgs_setup_set_original