ansible-later: 2.0.22 -> 2.0.23
[NixPkgs.git] / pkgs / stdenv / generic / setup.sh
blob62f9121d73d6b60fab54cb4d08c462c84d1f6080
1 # shellcheck shell=bash
2 __nixpkgs_setup_set_original=$-
3 set -eu
4 set -o pipefail
6 if [[ -n "${BASH_VERSINFO-}" && "${BASH_VERSINFO-}" -lt 4 ]]; then
7 echo "Detected Bash version that isn't supported by Nixpkgs (${BASH_VERSION})"
8 echo "Please install Bash 4 or greater to continue."
9 exit 1
12 shopt -s inherit_errexit
14 if (( "${NIX_DEBUG:-0}" >= 6 )); then
15 set -x
18 : ${outputs:=out}
21 ######################################################################
22 # Hook handling.
25 # Run all hooks with the specified name in the order in which they
26 # were added, stopping if any fails (returns a non-zero exit
27 # code). The hooks for <hookName> are the shell function or variable
28 # <hookName>, and the values of the shell array ‘<hookName>Hooks’.
29 runHook() {
30 local hookName="$1"
31 shift
32 local hooksSlice="${hookName%Hook}Hooks[@]"
34 local hook
35 # Hack around old bash being bad and thinking empty arrays are
36 # undefined.
37 for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do
38 _eval "$hook" "$@"
39 done
41 return 0
45 # Run all hooks with the specified name, until one succeeds (returns a
46 # zero exit code). If none succeed, return a non-zero exit code.
47 runOneHook() {
48 local hookName="$1"
49 shift
50 local hooksSlice="${hookName%Hook}Hooks[@]"
52 local hook ret=1
53 # Hack around old bash like above
54 for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do
55 if _eval "$hook" "$@"; then
56 ret=0
57 break
59 done
61 return "$ret"
65 # Run the named hook, either by calling the function with that name or
66 # by evaluating the variable with that name. This allows convenient
67 # setting of hooks both from Nix expressions (as attributes /
68 # environment variables) and from shell scripts (as functions). If you
69 # want to allow multiple hooks, use runHook instead.
70 _callImplicitHook() {
71 local def="$1"
72 local hookName="$2"
73 if declare -F "$hookName" > /dev/null; then
74 "$hookName"
75 elif type -p "$hookName" > /dev/null; then
76 source "$hookName"
77 elif [ -n "${!hookName:-}" ]; then
78 eval "${!hookName}"
79 else
80 return "$def"
82 # `_eval` expects hook to need nounset disable and leave it
83 # disabled anyways, so Ok to to delegate. The alternative of a
84 # return trap is no good because it would affect nested returns.
88 # A function wrapper around ‘eval’ that ensures that ‘return’ inside
89 # hooks exits the hook, not the caller. Also will only pass args if
90 # command can take them
91 _eval() {
92 if declare -F "$1" > /dev/null 2>&1; then
93 "$@" # including args
94 else
95 eval "$1"
100 ######################################################################
101 # Logging.
103 # Obsolete.
104 stopNest() { true; }
105 header() { echo "$1"; }
106 closeNest() { true; }
108 # Prints a command such that all word splits are unambiguous. We need
109 # to split the command in three parts because the middle format string
110 # will be, and must be, repeated for each argument. The first argument
111 # goes before the ':' and is just for convenience.
112 echoCmd() {
113 printf "%s:" "$1"
114 shift
115 printf ' %q' "$@"
116 echo
120 ######################################################################
121 # Error handling.
123 exitHandler() {
124 exitCode="$?"
125 set +e
127 if [ -n "${showBuildStats:-}" ]; then
128 read -r -d '' -a buildTimes < <(times)
129 echo "build times:"
130 echo "user time for the shell ${buildTimes[0]}"
131 echo "system time for the shell ${buildTimes[1]}"
132 echo "user time for all child processes ${buildTimes[2]}"
133 echo "system time for all child processes ${buildTimes[3]}"
136 if (( "$exitCode" != 0 )); then
137 runHook failureHook
139 # If the builder had a non-zero exit code and
140 # $succeedOnFailure is set, create the file
141 # ‘$out/nix-support/failed’ to signal failure, and exit
142 # normally. Otherwise, return the original exit code.
143 if [ -n "${succeedOnFailure:-}" ]; then
144 echo "build failed with exit code $exitCode (ignored)"
145 mkdir -p "$out/nix-support"
146 printf "%s" "$exitCode" > "$out/nix-support/failed"
147 return 0
150 else
151 runHook exitHook
154 return "$exitCode"
157 trap "exitHandler" EXIT
160 ######################################################################
161 # Helper functions.
164 addToSearchPathWithCustomDelimiter() {
165 local delimiter="$1"
166 local varName="$2"
167 local dir="$3"
168 if [[ -d "$dir" && "${!varName:+${delimiter}${!varName}${delimiter}}" \
169 != *"${delimiter}${dir}${delimiter}"* ]]; then
170 export "${varName}=${!varName:+${!varName}${delimiter}}${dir}"
174 addToSearchPath() {
175 addToSearchPathWithCustomDelimiter ":" "$@"
178 # Add $1/lib* into rpaths.
179 # The function is used in multiple-outputs.sh hook,
180 # so it is defined here but tried after the hook.
181 _addRpathPrefix() {
182 if [ "${NIX_NO_SELF_RPATH:-0}" != 1 ]; then
183 export NIX_LDFLAGS="-rpath $1/lib ${NIX_LDFLAGS-}"
184 if [ -n "${NIX_LIB64_IN_SELF_RPATH:-}" ]; then
185 export NIX_LDFLAGS="-rpath $1/lib64 ${NIX_LDFLAGS-}"
187 if [ -n "${NIX_LIB32_IN_SELF_RPATH:-}" ]; then
188 export NIX_LDFLAGS="-rpath $1/lib32 ${NIX_LDFLAGS-}"
193 # Return success if the specified file is an ELF object.
194 isELF() {
195 local fn="$1"
196 local fd
197 local magic
198 exec {fd}< "$fn"
199 read -r -n 4 -u "$fd" magic
200 exec {fd}<&-
201 if [ "$magic" = $'\177ELF' ]; then return 0; else return 1; fi
204 # Return success if the specified file is a Mach-O object.
205 isMachO() {
206 local fn="$1"
207 local fd
208 local magic
209 exec {fd}< "$fn"
210 read -r -n 4 -u "$fd" magic
211 exec {fd}<&-
213 # nix uses 'declare -F' in get-env.sh to retrieve the loaded functions.
214 # If we use the $'string' syntax instead of 'echo -ne' then 'declare' will print the raw characters and break nix.
215 # See https://github.com/NixOS/nixpkgs/pull/138334 and https://github.com/NixOS/nix/issues/5262.
217 # https://opensource.apple.com/source/lldb/lldb-310.2.36/examples/python/mach_o.py.auto.html
218 if [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xcf") || "$magic" = $(echo -ne "\xcf\xfa\xed\xfe") ]]; then
219 # MH_MAGIC_64 || MH_CIGAM_64
220 return 0;
221 elif [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xce") || "$magic" = $(echo -ne "\xce\xfa\xed\xfe") ]]; then
222 # MH_MAGIC || MH_CIGAM
223 return 0;
224 elif [[ "$magic" = $(echo -ne "\xca\xfe\xba\xbe") || "$magic" = $(echo -ne "\xbe\xba\xfe\xca") ]]; then
225 # FAT_MAGIC || FAT_CIGAM
226 return 0;
227 else
228 return 1;
232 # Return success if the specified file is a script (i.e. starts with
233 # "#!").
234 isScript() {
235 local fn="$1"
236 local fd
237 local magic
238 exec {fd}< "$fn"
239 read -r -n 2 -u "$fd" magic
240 exec {fd}<&-
241 if [[ "$magic" =~ \#! ]]; then return 0; else return 1; fi
244 # printf unfortunately will print a trailing newline regardless
245 printLines() {
246 (( "$#" > 0 )) || return 0
247 printf '%s\n' "$@"
250 printWords() {
251 (( "$#" > 0 )) || return 0
252 printf '%s ' "$@"
255 ######################################################################
256 # Initialisation.
259 # Set a fallback default value for SOURCE_DATE_EPOCH, used by some build tools
260 # to provide a deterministic substitute for the "current" time. Note that
261 # 315532800 = 1980-01-01 12:00:00. We use this date because python's wheel
262 # implementation uses zip archive and zip does not support dates going back to
263 # 1970.
264 export SOURCE_DATE_EPOCH
265 : ${SOURCE_DATE_EPOCH:=315532800}
268 # Wildcard expansions that don't match should expand to an empty list.
269 # This ensures that, for instance, "for i in *; do ...; done" does the
270 # right thing.
271 shopt -s nullglob
274 # Set up the initial path.
275 PATH=
276 HOST_PATH=
277 for i in $initialPath; do
278 if [ "$i" = / ]; then i=; fi
279 addToSearchPath PATH "$i/bin"
281 # For backward compatibility, we add initial path to HOST_PATH so
282 # it can be used in auto patch-shebangs. Unfortunately this will
283 # not work with cross compilation.
284 if [ -z "${strictDeps-}" ]; then
285 addToSearchPath HOST_PATH "$i/bin"
287 done
289 unset i
291 if (( "${NIX_DEBUG:-0}" >= 1 )); then
292 echo "initial path: $PATH"
296 # Check that the pre-hook initialised SHELL.
297 if [ -z "${SHELL:-}" ]; then echo "SHELL not set"; exit 1; fi
298 BASH="$SHELL"
299 export CONFIG_SHELL="$SHELL"
302 # Execute the pre-hook.
303 if [ -z "${shell:-}" ]; then export shell="$SHELL"; fi
304 runHook preHook
307 # Allow the caller to augment buildInputs (it's not always possible to
308 # do this before the call to setup.sh, since the PATH is empty at that
309 # point; here we have a basic Unix environment).
310 runHook addInputsHook
313 # Package accumulators
315 # shellcheck disable=SC2034
316 declare -a pkgsBuildBuild pkgsBuildHost pkgsBuildTarget
317 declare -a pkgsHostHost pkgsHostTarget
318 declare -a pkgsTargetTarget
320 declare -a pkgBuildAccumVars=(pkgsBuildBuild pkgsBuildHost pkgsBuildTarget)
321 declare -a pkgHostAccumVars=(pkgsHostHost pkgsHostTarget)
322 declare -a pkgTargetAccumVars=(pkgsTargetTarget)
324 declare -a pkgAccumVarVars=(pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars)
327 # Hooks
329 declare -a envBuildBuildHooks envBuildHostHooks envBuildTargetHooks
330 declare -a envHostHostHooks envHostTargetHooks
331 declare -a envTargetTargetHooks
333 declare -a pkgBuildHookVars=(envBuildBuildHook envBuildHostHook envBuildTargetHook)
334 declare -a pkgHostHookVars=(envHostHostHook envHostTargetHook)
335 declare -a pkgTargetHookVars=(envTargetTargetHook)
337 declare -a pkgHookVarVars=(pkgBuildHookVars pkgHostHookVars pkgTargetHookVars)
339 # those variables are declared here, since where and if they are used varies
340 # shellcheck disable=SC2034
341 declare -a preFixupHooks fixupOutputHooks preConfigureHooks postFixupHooks postUnpackHooks unpackCmdHooks
343 # Add env hooks for all sorts of deps with the specified host offset.
344 addEnvHooks() {
345 local depHostOffset="$1"
346 shift
347 local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]"
348 local pkgHookVar
349 for pkgHookVar in "${!pkgHookVarsSlice}"; do
350 eval "${pkgHookVar}s"'+=("$@")'
351 done
355 # Propagated dep files
357 declare -a propagatedBuildDepFiles=(
358 propagated-build-build-deps
359 propagated-native-build-inputs # Legacy name for back-compat
360 propagated-build-target-deps
362 declare -a propagatedHostDepFiles=(
363 propagated-host-host-deps
364 propagated-build-inputs # Legacy name for back-compat
366 declare -a propagatedTargetDepFiles=(
367 propagated-target-target-deps
369 declare -a propagatedDepFilesVars=(
370 propagatedBuildDepFiles
371 propagatedHostDepFiles
372 propagatedTargetDepFiles
375 # Platform offsets: build = -1, host = 0, target = 1
376 declare -a allPlatOffsets=(-1 0 1)
379 # Mutually-recursively find all build inputs. See the dependency section of the
380 # stdenv chapter of the Nixpkgs manual for the specification this algorithm
381 # implements.
382 findInputs() {
383 local -r pkg="$1"
384 local -r hostOffset="$2"
385 local -r targetOffset="$3"
387 # Sanity check
388 (( hostOffset <= targetOffset )) || exit -1
390 local varVar="${pkgAccumVarVars[hostOffset + 1]}"
391 local varRef="$varVar[$((targetOffset - hostOffset))]"
392 local var="${!varRef}"
393 unset -v varVar varRef
395 # TODO(@Ericson2314): Restore using associative array once Darwin
396 # nix-shell doesn't use impure bash. This should replace the O(n)
397 # case with an O(1) hash map lookup, assuming bash is implemented
398 # well :D.
399 local varSlice="$var[*]"
400 # ${..-} to hack around old bash empty array problem
401 case "${!varSlice-}" in
402 *" $pkg "*) return 0 ;;
403 esac
404 unset -v varSlice
406 eval "$var"'+=("$pkg")'
408 if ! [ -e "$pkg" ]; then
409 echo "build input $pkg does not exist" >&2
410 exit 1
413 # The current package's host and target offset together
414 # provide a <=-preserving homomorphism from the relative
415 # offsets to current offset
416 function mapOffset() {
417 local -r inputOffset="$1"
418 local -n outputOffset="$2"
419 if (( inputOffset <= 0 )); then
420 outputOffset=$((inputOffset + hostOffset))
421 else
422 outputOffset=$((inputOffset - 1 + targetOffset))
426 # Host offset relative to that of the package whose immediate
427 # dependencies we are currently exploring.
428 local relHostOffset
429 for relHostOffset in "${allPlatOffsets[@]}"; do
430 # `+ 1` so we start at 0 for valid index
431 local files="${propagatedDepFilesVars[relHostOffset + 1]}"
433 # Host offset relative to the package currently being
434 # built---as absolute an offset as will be used.
435 local hostOffsetNext
436 mapOffset "$relHostOffset" hostOffsetNext
438 # Ensure we're in bounds relative to the package currently
439 # being built.
440 (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue
442 # Target offset relative to the *host* offset of the package
443 # whose immediate dependencies we are currently exploring.
444 local relTargetOffset
445 for relTargetOffset in "${allPlatOffsets[@]}"; do
446 (( "$relHostOffset" <= "$relTargetOffset" )) || continue
448 local fileRef="${files}[$relTargetOffset - $relHostOffset]"
449 local file="${!fileRef}"
450 unset -v fileRef
452 # Target offset relative to the package currently being
453 # built.
454 local targetOffsetNext
455 mapOffset "$relTargetOffset" targetOffsetNext
457 # Once again, ensure we're in bounds relative to the
458 # package currently being built.
459 (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue
461 [[ -f "$pkg/nix-support/$file" ]] || continue
463 local pkgNext
464 read -r -d '' pkgNext < "$pkg/nix-support/$file" || true
465 for pkgNext in $pkgNext; do
466 findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext"
467 done
468 done
469 done
472 # Make sure all are at least defined as empty
473 : ${depsBuildBuild=} ${depsBuildBuildPropagated=}
474 : ${nativeBuildInputs=} ${propagatedNativeBuildInputs=} ${defaultNativeBuildInputs=}
475 : ${depsBuildTarget=} ${depsBuildTargetPropagated=}
476 : ${depsHostHost=} ${depsHostHostPropagated=}
477 : ${buildInputs=} ${propagatedBuildInputs=} ${defaultBuildInputs=}
478 : ${depsTargetTarget=} ${depsTargetTargetPropagated=}
480 for pkg in $depsBuildBuild $depsBuildBuildPropagated; do
481 findInputs "$pkg" -1 -1
482 done
483 for pkg in $nativeBuildInputs $propagatedNativeBuildInputs; do
484 findInputs "$pkg" -1 0
485 done
486 for pkg in $depsBuildTarget $depsBuildTargetPropagated; do
487 findInputs "$pkg" -1 1
488 done
489 for pkg in $depsHostHost $depsHostHostPropagated; do
490 findInputs "$pkg" 0 0
491 done
492 for pkg in $buildInputs $propagatedBuildInputs ; do
493 findInputs "$pkg" 0 1
494 done
495 for pkg in $depsTargetTarget $depsTargetTargetPropagated; do
496 findInputs "$pkg" 1 1
497 done
498 # Default inputs must be processed last
499 for pkg in $defaultNativeBuildInputs; do
500 findInputs "$pkg" -1 0
501 done
502 for pkg in $defaultBuildInputs; do
503 findInputs "$pkg" 0 1
504 done
506 # Add package to the future PATH and run setup hooks
507 activatePackage() {
508 local pkg="$1"
509 local -r hostOffset="$2"
510 local -r targetOffset="$3"
512 # Sanity check
513 (( hostOffset <= targetOffset )) || exit -1
515 if [ -f "$pkg" ]; then
516 source "$pkg"
519 # Only dependencies whose host platform is guaranteed to match the
520 # build platform are included here. That would be `depsBuild*`,
521 # and legacy `nativeBuildInputs`, in general. If we aren't cross
522 # compiling, however, everything can be put on the PATH. To ease
523 # the transition, we do include everything in that case.
525 # TODO(@Ericson2314): Don't special-case native compilation
526 if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then
527 addToSearchPath _PATH "$pkg/bin"
530 if (( hostOffset <= -1 )); then
531 addToSearchPath _XDG_DATA_DIRS "$pkg/share"
534 if [[ "$hostOffset" -eq 0 && -d "$pkg/bin" ]]; then
535 addToSearchPath _HOST_PATH "$pkg/bin"
538 if [[ -f "$pkg/nix-support/setup-hook" ]]; then
539 source "$pkg/nix-support/setup-hook"
543 _activatePkgs() {
544 local hostOffset targetOffset
545 local pkg
547 for hostOffset in "${allPlatOffsets[@]}"; do
548 local pkgsVar="${pkgAccumVarVars[hostOffset + 1]}"
549 for targetOffset in "${allPlatOffsets[@]}"; do
550 (( hostOffset <= targetOffset )) || continue
551 local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]"
552 local pkgsSlice="${!pkgsRef}[@]"
553 for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do
554 activatePackage "$pkg" "$hostOffset" "$targetOffset"
555 done
556 done
557 done
560 # Run the package setup hooks and build _PATH
561 _activatePkgs
563 # Set the relevant environment variables to point to the build inputs
564 # found above.
566 # These `depOffset`s, beyond indexing the arrays, also tell the env
567 # hook what sort of dependency (ignoring propagatedness) is being
568 # passed to the env hook. In a real language, we'd append a closure
569 # with this information to the relevant env hook array, but bash
570 # doesn't have closures, so it's easier to just pass this in.
571 _addToEnv() {
572 local depHostOffset depTargetOffset
573 local pkg
575 for depHostOffset in "${allPlatOffsets[@]}"; do
576 local hookVar="${pkgHookVarVars[depHostOffset + 1]}"
577 local pkgsVar="${pkgAccumVarVars[depHostOffset + 1]}"
578 for depTargetOffset in "${allPlatOffsets[@]}"; do
579 (( depHostOffset <= depTargetOffset )) || continue
580 local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]"
581 if [[ -z "${strictDeps-}" ]]; then
583 # Keep track of which packages we have visited before.
584 local visitedPkgs=""
586 # Apply environment hooks to all packages during native
587 # compilation to ease the transition.
589 # TODO(@Ericson2314): Don't special-case native compilation
590 for pkg in \
591 "${pkgsBuildBuild[@]}" \
592 "${pkgsBuildHost[@]}" \
593 "${pkgsBuildTarget[@]}" \
594 "${pkgsHostHost[@]}" \
595 "${pkgsHostTarget[@]}" \
596 "${pkgsTargetTarget[@]}"
598 if [[ "$visitedPkgs" = *"$pkg"* ]]; then
599 continue
601 runHook "${!hookRef}" "$pkg"
602 visitedPkgs+=" $pkg"
603 done
604 else
605 local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]"
606 local pkgsSlice="${!pkgsRef}[@]"
607 for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do
608 runHook "${!hookRef}" "$pkg"
609 done
611 done
612 done
615 # Run the package-specific hooks set by the setup-hook scripts.
616 _addToEnv
619 # Unset setup-specific declared variables
620 unset allPlatOffsets
621 unset pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars pkgAccumVarVars
622 unset pkgBuildHookVars pkgHostHookVars pkgTargetHookVars pkgHookVarVars
623 unset propagatedDepFilesVars
626 _addRpathPrefix "$out"
629 # Set the TZ (timezone) environment variable, otherwise commands like
630 # `date' will complain (e.g., `Tue Mar 9 10:01:47 Local time zone must
631 # be set--see zic manual page 2004').
632 export TZ=UTC
635 # Set the prefix. This is generally $out, but it can be overriden,
636 # for instance if we just want to perform a test build/install to a
637 # temporary location and write a build report to $out.
638 if [ -z "${prefix:-}" ]; then
639 prefix="$out";
642 if [ "${useTempPrefix:-}" = 1 ]; then
643 prefix="$NIX_BUILD_TOP/tmp_prefix";
647 PATH="${_PATH-}${_PATH:+${PATH:+:}}$PATH"
648 HOST_PATH="${_HOST_PATH-}${_HOST_PATH:+${HOST_PATH:+:}}$HOST_PATH"
649 export XDG_DATA_DIRS="${_XDG_DATA_DIRS-}${_XDG_DATA_DIRS:+${XDG_DATA_DIRS:+:}}${XDG_DATA_DIRS-}"
650 if (( "${NIX_DEBUG:-0}" >= 1 )); then
651 echo "final path: $PATH"
652 echo "final host path: $HOST_PATH"
653 echo "final data dirs: $XDG_DATA_DIRS"
656 unset _PATH
657 unset _HOST_PATH
658 unset _XDG_DATA_DIRS
661 # Make GNU Make produce nested output.
662 export NIX_INDENT_MAKE=1
665 # Normalize the NIX_BUILD_CORES variable. The value might be 0, which
666 # means that we're supposed to try and auto-detect the number of
667 # available CPU cores at run-time.
669 NIX_BUILD_CORES="${NIX_BUILD_CORES:-1}"
670 if ((NIX_BUILD_CORES <= 0)); then
671 guess=$(nproc 2>/dev/null || true)
672 ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess))
674 export NIX_BUILD_CORES
677 # Prevent SSL libraries from using certificates in /etc/ssl, unless set explicitly.
678 # Leave it in impure shells for convenience.
679 if [[ -z "${NIX_SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]; then
680 export NIX_SSL_CERT_FILE=/no-cert-file.crt
682 # Another variant left for compatibility.
683 if [[ -z "${SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]; then
684 export SSL_CERT_FILE=/no-cert-file.crt
688 ######################################################################
689 # Textual substitution functions.
692 substituteStream() {
693 local var=$1
694 local description=$2
695 shift 2
697 while (( "$#" )); do
698 case "$1" in
699 --replace)
700 pattern="$2"
701 replacement="$3"
702 shift 3
703 local savedvar
704 savedvar="${!var}"
705 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
706 if [ "$pattern" != "$replacement" ]; then
707 if [ "${!var}" == "$savedvar" ]; then
708 echo "substituteStream(): WARNING: pattern '$pattern' doesn't match anything in $description" >&2
713 --subst-var)
714 local varName="$2"
715 shift 2
716 # check if the used nix attribute name is a valid bash name
717 if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
718 echo "substituteStream(): ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2
719 return 1
721 if [ -z ${!varName+x} ]; then
722 echo "substituteStream(): ERROR: variable \$$varName is unset" >&2
723 return 1
725 pattern="@$varName@"
726 replacement="${!varName}"
727 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
730 --subst-var-by)
731 pattern="@$2@"
732 replacement="$3"
733 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'
734 shift 3
738 echo "substituteStream(): ERROR: Invalid command line argument: $1" >&2
739 return 1
741 esac
742 done
744 printf "%s" "${!var}"
747 # put the content of a file in a variable
748 # fail loudly if provided with a binary (containing null bytes)
749 consumeEntire() {
750 # read returns non-0 on EOF, so we want read to fail
751 if IFS='' read -r -d '' $1 ; then
752 echo "consumeEntire(): ERROR: Input null bytes, won't process" >&2
753 return 1
757 substitute() {
758 local input="$1"
759 local output="$2"
760 shift 2
762 if [ ! -f "$input" ]; then
763 echo "substitute(): ERROR: file '$input' does not exist" >&2
764 return 1
767 local content
768 consumeEntire content < "$input"
770 if [ -e "$output" ]; then chmod +w "$output"; fi
771 substituteStream content "file '$input'" "$@" > "$output"
774 substituteInPlace() {
775 local -a fileNames=()
776 for arg in "$@"; do
777 if [[ "$arg" = "--"* ]]; then
778 break
780 fileNames+=("$arg")
781 shift
782 done
784 for file in "${fileNames[@]}"; do
785 substitute "$file" "$file" "$@"
786 done
789 _allFlags() {
790 for varName in $(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }'); do
791 if (( "${NIX_DEBUG:-0}" >= 1 )); then
792 printf "@%s@ -> %q\n" "${varName}" "${!varName}"
794 args+=("--subst-var" "$varName")
795 done
798 substituteAllStream() {
799 local -a args=()
800 _allFlags
802 substituteStream "$1" "$2" "${args[@]}"
805 # Substitute all environment variables that start with a lowercase character and
806 # are valid Bash names.
807 substituteAll() {
808 local input="$1"
809 local output="$2"
811 local -a args=()
812 _allFlags
814 substitute "$input" "$output" "${args[@]}"
818 substituteAllInPlace() {
819 local fileName="$1"
820 shift
821 substituteAll "$fileName" "$fileName" "$@"
825 ######################################################################
826 # What follows is the generic builder.
829 # This function is useful for debugging broken Nix builds. It dumps
830 # all environment variables to a file `env-vars' in the build
831 # directory. If the build fails and the `-K' option is used, you can
832 # then go to the build directory and source in `env-vars' to reproduce
833 # the environment used for building.
834 dumpVars() {
835 if [ "${noDumpEnvVars:-0}" != 1 ]; then
836 export 2>/dev/null >| "$NIX_BUILD_TOP/env-vars" || true
841 # Utility function: echo the base name of the given path, with the
842 # prefix `HASH-' removed, if present.
843 stripHash() {
844 local strippedName casematchOpt=0
845 # On separate line for `set -e`
846 strippedName="$(basename -- "$1")"
847 shopt -q nocasematch && casematchOpt=1
848 shopt -u nocasematch
849 if [[ "$strippedName" =~ ^[a-z0-9]{32}- ]]; then
850 echo "${strippedName:33}"
851 else
852 echo "$strippedName"
854 if (( casematchOpt )); then shopt -s nocasematch; fi
858 unpackCmdHooks+=(_defaultUnpack)
859 _defaultUnpack() {
860 local fn="$1"
862 if [ -d "$fn" ]; then
864 # We can't preserve hardlinks because they may have been
865 # introduced by store optimization, which might break things
866 # in the build.
867 cp -pr --reflink=auto -- "$fn" "$(stripHash "$fn")"
869 else
871 case "$fn" in
872 *.tar.xz | *.tar.lzma | *.txz)
873 # Don't rely on tar knowing about .xz.
874 xz -d < "$fn" | tar xf - --warning=no-timestamp
876 *.tar | *.tar.* | *.tgz | *.tbz2 | *.tbz)
877 # GNU tar can automatically select the decompression method
878 # (info "(tar) gzip").
879 tar xf "$fn" --warning=no-timestamp
882 return 1
884 esac
890 unpackFile() {
891 curSrc="$1"
892 header "unpacking source archive $curSrc" 3
893 if ! runOneHook unpackCmd "$curSrc"; then
894 echo "do not know how to unpack source archive $curSrc"
895 exit 1
900 unpackPhase() {
901 runHook preUnpack
903 if [ -z "${srcs:-}" ]; then
904 if [ -z "${src:-}" ]; then
905 # shellcheck disable=SC2016
906 echo 'variable $src or $srcs should point to the source'
907 exit 1
909 srcs="$src"
912 # To determine the source directory created by unpacking the
913 # source archives, we record the contents of the current
914 # directory, then look below which directory got added. Yeah,
915 # it's rather hacky.
916 local dirsBefore=""
917 for i in *; do
918 if [ -d "$i" ]; then
919 dirsBefore="$dirsBefore $i "
921 done
923 # Unpack all source archives.
924 for i in $srcs; do
925 unpackFile "$i"
926 done
928 # Find the source directory.
930 # set to empty if unset
931 : ${sourceRoot=}
933 if [ -n "${setSourceRoot:-}" ]; then
934 runOneHook setSourceRoot
935 elif [ -z "$sourceRoot" ]; then
936 for i in *; do
937 if [ -d "$i" ]; then
938 case $dirsBefore in
939 *\ $i\ *)
942 if [ -n "$sourceRoot" ]; then
943 echo "unpacker produced multiple directories"
944 exit 1
946 sourceRoot="$i"
948 esac
950 done
953 if [ -z "$sourceRoot" ]; then
954 echo "unpacker appears to have produced no directories"
955 exit 1
958 echo "source root is $sourceRoot"
960 # By default, add write permission to the sources. This is often
961 # necessary when sources have been copied from other store
962 # locations.
963 if [ "${dontMakeSourcesWritable:-0}" != 1 ]; then
964 chmod -R u+w -- "$sourceRoot"
967 runHook postUnpack
971 patchPhase() {
972 runHook prePatch
974 for i in ${patches:-}; do
975 header "applying patch $i" 3
976 local uncompress=cat
977 case "$i" in
978 *.gz)
979 uncompress="gzip -d"
981 *.bz2)
982 uncompress="bzip2 -d"
984 *.xz)
985 uncompress="xz -d"
987 *.lzma)
988 uncompress="lzma -d"
990 esac
991 # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.)
992 # shellcheck disable=SC2086
993 $uncompress < "$i" 2>&1 | patch ${patchFlags:--p1}
994 done
996 runHook postPatch
1000 fixLibtool() {
1001 local search_path
1002 for flag in $NIX_LDFLAGS; do
1003 case $flag in
1004 -L*)
1005 search_path+=" ${flag#-L}"
1007 esac
1008 done
1010 sed -i "$1" \
1011 -e "s^eval \(sys_lib_search_path=\).*^\1'$search_path'^" \
1012 -e 's^eval sys_lib_.+search_path=.*^^'
1016 configurePhase() {
1017 runHook preConfigure
1019 # set to empty if unset
1020 : ${configureScript=}
1021 : ${configureFlags=}
1023 if [[ -z "$configureScript" && -x ./configure ]]; then
1024 configureScript=./configure
1027 if [ -z "${dontFixLibtool:-}" ]; then
1028 export lt_cv_deplibs_check_method="${lt_cv_deplibs_check_method-pass_all}"
1029 local i
1030 find . -iname "ltmain.sh" -print0 | while IFS='' read -r -d '' i; do
1031 echo "fixing libtool script $i"
1032 fixLibtool "$i"
1033 done
1035 # replace `/usr/bin/file` with `file` in any `configure`
1036 # scripts with vendored libtool code. Preserve mtimes to
1037 # prevent some packages (e.g. libidn2) from spontaneously
1038 # autoreconf'ing themselves
1039 CONFIGURE_MTIME_REFERENCE=$(mktemp configure.mtime.reference.XXXXXX)
1040 find . \
1041 -executable \
1042 -type f \
1043 -name configure \
1044 -exec grep -l 'GNU Libtool is free software; you can redistribute it and/or modify' {} \; \
1045 -exec touch -r {} "$CONFIGURE_MTIME_REFERENCE" \; \
1046 -exec sed -i s_/usr/bin/file_file_g {} \; \
1047 -exec touch -r "$CONFIGURE_MTIME_REFERENCE" {} \;
1048 rm -f "$CONFIGURE_MTIME_REFERENCE"
1051 if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then
1052 configureFlags="${prefixKey:---prefix=}$prefix $configureFlags"
1055 if [[ -f "$configureScript" ]]; then
1056 # Add --disable-dependency-tracking to speed up some builds.
1057 if [ -z "${dontAddDisableDepTrack:-}" ]; then
1058 if grep -q dependency-tracking "$configureScript"; then
1059 configureFlags="--disable-dependency-tracking $configureFlags"
1063 # By default, disable static builds.
1064 if [ -z "${dontDisableStatic:-}" ]; then
1065 if grep -q enable-static "$configureScript"; then
1066 configureFlags="--disable-static $configureFlags"
1071 if [ -n "$configureScript" ]; then
1072 # Old bash empty array hack
1073 # shellcheck disable=SC2086
1074 local flagsArray=(
1075 $configureFlags "${configureFlagsArray[@]}"
1077 echoCmd 'configure flags' "${flagsArray[@]}"
1078 # shellcheck disable=SC2086
1079 $configureScript "${flagsArray[@]}"
1080 unset flagsArray
1081 else
1082 echo "no configure script, doing nothing"
1085 runHook postConfigure
1089 buildPhase() {
1090 runHook preBuild
1092 # set to empty if unset
1093 : ${makeFlags=}
1095 if [[ -z "$makeFlags" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then
1096 echo "no Makefile, doing nothing"
1097 else
1098 foundMakefile=1
1100 # Old bash empty array hack
1101 # shellcheck disable=SC2086
1102 local flagsArray=(
1103 ${enableParallelBuilding:+-j${NIX_BUILD_CORES}}
1104 SHELL=$SHELL
1105 $makeFlags "${makeFlagsArray[@]}"
1106 $buildFlags "${buildFlagsArray[@]}"
1109 echoCmd 'build flags' "${flagsArray[@]}"
1110 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1111 unset flagsArray
1114 runHook postBuild
1118 checkPhase() {
1119 runHook preCheck
1121 if [[ -z "${foundMakefile:-}" ]]; then
1122 echo "no Makefile or custom checkPhase, doing nothing"
1123 runHook postCheck
1124 return
1127 if [[ -z "${checkTarget:-}" ]]; then
1128 #TODO(@oxij): should flagsArray influence make -n?
1129 if make -n ${makefile:+-f $makefile} check >/dev/null 2>&1; then
1130 checkTarget=check
1131 elif make -n ${makefile:+-f $makefile} test >/dev/null 2>&1; then
1132 checkTarget=test
1136 if [[ -z "${checkTarget:-}" ]]; then
1137 echo "no check/test target in ${makefile:-Makefile}, doing nothing"
1138 else
1139 # Old bash empty array hack
1140 # shellcheck disable=SC2086
1141 local flagsArray=(
1142 ${enableParallelChecking:+-j${NIX_BUILD_CORES}}
1143 SHELL=$SHELL
1144 $makeFlags "${makeFlagsArray[@]}"
1145 ${checkFlags:-VERBOSE=y} "${checkFlagsArray[@]}"
1146 ${checkTarget}
1149 echoCmd 'check flags' "${flagsArray[@]}"
1150 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1152 unset flagsArray
1155 runHook postCheck
1159 installPhase() {
1160 runHook preInstall
1162 if [ -n "$prefix" ]; then
1163 mkdir -p "$prefix"
1166 # Old bash empty array hack
1167 # shellcheck disable=SC2086
1168 local flagsArray=(
1169 SHELL=$SHELL
1170 $makeFlags "${makeFlagsArray[@]}"
1171 $installFlags "${installFlagsArray[@]}"
1172 ${installTargets:-install}
1175 echoCmd 'install flags' "${flagsArray[@]}"
1176 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1177 unset flagsArray
1179 runHook postInstall
1183 # The fixup phase performs generic, package-independent stuff, like
1184 # stripping binaries, running patchelf and setting
1185 # propagated-build-inputs.
1186 fixupPhase() {
1187 # Make sure everything is writable so "strip" et al. work.
1188 local output
1189 for output in $outputs; do
1190 if [ -e "${!output}" ]; then chmod -R u+w "${!output}"; fi
1191 done
1193 runHook preFixup
1195 # Apply fixup to each output.
1196 local output
1197 for output in $outputs; do
1198 prefix="${!output}" runHook fixupOutput
1199 done
1202 # Propagate dependencies & setup hook into the development output.
1203 declare -ra flatVars=(
1204 # Build
1205 depsBuildBuildPropagated
1206 propagatedNativeBuildInputs
1207 depsBuildTargetPropagated
1208 # Host
1209 depsHostHostPropagated
1210 propagatedBuildInputs
1211 # Target
1212 depsTargetTargetPropagated
1214 declare -ra flatFiles=(
1215 "${propagatedBuildDepFiles[@]}"
1216 "${propagatedHostDepFiles[@]}"
1217 "${propagatedTargetDepFiles[@]}"
1220 local propagatedInputsIndex
1221 for propagatedInputsIndex in "${!flatVars[@]}"; do
1222 local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]"
1223 local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}"
1225 [[ "${!propagatedInputsSlice}" ]] || continue
1227 mkdir -p "${!outputDev}/nix-support"
1228 # shellcheck disable=SC2086
1229 printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile"
1230 done
1233 if [ -n "${setupHook:-}" ]; then
1234 mkdir -p "${!outputDev}/nix-support"
1235 substituteAll "$setupHook" "${!outputDev}/nix-support/setup-hook"
1238 # TODO(@Ericson2314): Remove after https://github.com/NixOS/nixpkgs/pull/31414
1239 if [ -n "${setupHooks:-}" ]; then
1240 mkdir -p "${!outputDev}/nix-support"
1241 local hook
1242 for hook in $setupHooks; do
1243 local content
1244 consumeEntire content < "$hook"
1245 substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook"
1246 unset -v content
1247 done
1248 unset -v hook
1251 # Propagate user-env packages into the output with binaries, TODO?
1253 if [ -n "${propagatedUserEnvPkgs:-}" ]; then
1254 mkdir -p "${!outputBin}/nix-support"
1255 # shellcheck disable=SC2086
1256 printWords $propagatedUserEnvPkgs > "${!outputBin}/nix-support/propagated-user-env-packages"
1259 runHook postFixup
1263 installCheckPhase() {
1264 runHook preInstallCheck
1266 if [[ -z "${foundMakefile:-}" ]]; then
1267 echo "no Makefile or custom installCheckPhase, doing nothing"
1268 #TODO(@oxij): should flagsArray influence make -n?
1269 elif [[ -z "${installCheckTarget:-}" ]] \
1270 && ! make -n ${makefile:+-f $makefile} ${installCheckTarget:-installcheck} >/dev/null 2>&1; then
1271 echo "no installcheck target in ${makefile:-Makefile}, doing nothing"
1272 else
1273 # Old bash empty array hack
1274 # shellcheck disable=SC2086
1275 local flagsArray=(
1276 ${enableParallelChecking:+-j${NIX_BUILD_CORES}}
1277 SHELL=$SHELL
1278 $makeFlags "${makeFlagsArray[@]}"
1279 $installCheckFlags "${installCheckFlagsArray[@]}"
1280 ${installCheckTarget:-installcheck}
1283 echoCmd 'installcheck flags' "${flagsArray[@]}"
1284 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1285 unset flagsArray
1288 runHook postInstallCheck
1292 distPhase() {
1293 runHook preDist
1295 # Old bash empty array hack
1296 # shellcheck disable=SC2086
1297 local flagsArray=(
1298 $distFlags "${distFlagsArray[@]}" ${distTarget:-dist}
1301 echo 'dist flags: %q' "${flagsArray[@]}"
1302 make ${makefile:+-f $makefile} "${flagsArray[@]}"
1304 if [ "${dontCopyDist:-0}" != 1 ]; then
1305 mkdir -p "$out/tarballs"
1307 # Note: don't quote $tarballs, since we explicitly permit
1308 # wildcards in there.
1309 # shellcheck disable=SC2086
1310 cp -pvd ${tarballs:-*.tar.gz} "$out/tarballs"
1313 runHook postDist
1317 showPhaseHeader() {
1318 local phase="$1"
1319 case "$phase" in
1320 unpackPhase) header "unpacking sources";;
1321 patchPhase) header "patching sources";;
1322 configurePhase) header "configuring";;
1323 buildPhase) header "building";;
1324 checkPhase) header "running tests";;
1325 installPhase) header "installing";;
1326 fixupPhase) header "post-installation fixup";;
1327 installCheckPhase) header "running install tests";;
1328 *) header "$phase";;
1329 esac
1333 showPhaseFooter() {
1334 local phase="$1"
1335 local startTime="$2"
1336 local endTime="$3"
1337 local delta=$(( endTime - startTime ))
1338 (( $delta < 30 )) && return
1340 local H=$((delta/3600))
1341 local M=$((delta%3600/60))
1342 local S=$((delta%60))
1343 echo -n "$phase completed in "
1344 (( $H > 0 )) && echo -n "$H hours "
1345 (( $M > 0 )) && echo -n "$M minutes "
1346 echo "$S seconds"
1350 genericBuild() {
1351 if [ -f "${buildCommandPath:-}" ]; then
1352 source "$buildCommandPath"
1353 return
1355 if [ -n "${buildCommand:-}" ]; then
1356 eval "$buildCommand"
1357 return
1360 if [ -z "${phases:-}" ]; then
1361 phases="${prePhases:-} unpackPhase patchPhase ${preConfigurePhases:-} \
1362 configurePhase ${preBuildPhases:-} buildPhase checkPhase \
1363 ${preInstallPhases:-} installPhase ${preFixupPhases:-} fixupPhase installCheckPhase \
1364 ${preDistPhases:-} distPhase ${postPhases:-}";
1367 for curPhase in $phases; do
1368 if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then continue; fi
1369 if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then continue; fi
1370 if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then continue; fi
1371 if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then continue; fi
1372 if [[ "$curPhase" = checkPhase && -z "${doCheck:-}" ]]; then continue; fi
1373 if [[ "$curPhase" = installPhase && -n "${dontInstall:-}" ]]; then continue; fi
1374 if [[ "$curPhase" = fixupPhase && -n "${dontFixup:-}" ]]; then continue; fi
1375 if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then continue; fi
1376 if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then continue; fi
1378 if [[ -n $NIX_LOG_FD ]]; then
1379 echo "@nix { \"action\": \"setPhase\", \"phase\": \"$curPhase\" }" >&$NIX_LOG_FD
1382 showPhaseHeader "$curPhase"
1383 dumpVars
1385 local startTime=$(date +"%s")
1387 # Evaluate the variable named $curPhase if it exists, otherwise the
1388 # function named $curPhase.
1389 eval "${!curPhase:-$curPhase}"
1391 local endTime=$(date +"%s")
1393 showPhaseFooter "$curPhase" "$startTime" "$endTime"
1395 if [ "$curPhase" = unpackPhase ]; then
1396 # make sure we can cd into the directory
1397 [ -z "${sourceRoot}" ] || chmod +x "${sourceRoot}"
1399 cd "${sourceRoot:-.}"
1401 done
1405 # Execute the post-hooks.
1406 runHook postHook
1409 # Execute the global user hook (defined through the Nixpkgs
1410 # configuration option ‘stdenv.userHook’). This can be used to set
1411 # global compiler optimisation flags, for instance.
1412 runHook userHook
1415 dumpVars
1417 # Restore the original options for nix-shell
1418 [[ $__nixpkgs_setup_set_original == *e* ]] || set +e
1419 [[ $__nixpkgs_setup_set_original == *u* ]] || set +u
1420 unset -v __nixpkgs_setup_set_original