Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# shellcheck shell=bash 2# shellcheck disable=1090,2154,2123,2034,2178,2048,2068,1091 3__nixpkgs_setup_set_original=$- 4set -eu 5set -o pipefail 6 7if [[ -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 11fi 12 13shopt -s inherit_errexit 14 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. 17if ! [[ -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 22fi 23 24if [[ ${NIX_DEBUG:-0} -ge 6 ]]; then 25 set -x 26fi 27 28if [ -f .attrs.sh ] || [[ -n "${NIX_ATTRS_JSON_FILE:-}" ]]; then 29 __structuredAttrs=1 30 echo "structuredAttrs is enabled" 31 32 for outputName in "${!outputs[@]}"; do 33 # ex: out=/nix/store/... 34 export "$outputName=${outputs[$outputName]}" 35 done 36 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" 42 fi 43 if ! [[ -e "${NIX_ATTRS_SH_FILE:-}" ]]; then 44 export NIX_ATTRS_SH_FILE="$NIX_BUILD_TOP/.attrs.sh" 45 fi 46else 47 __structuredAttrs= 48 : "${outputs:=out}" 49fi 50 51getAllOutputNames() { 52 if [ -n "$__structuredAttrs" ]; then 53 echo "${!outputs[*]}" 54 else 55 echo "$outputs" 56 fi 57} 58 59# All provided arguments are joined with a space, then prefixed by the name of the function which invoked `nixLog` (or 60# the hook name if the caller was an implicit hook), then directed to $NIX_LOG_FD, if it's set. 61nixLog() { 62 # Return a value explicitly instead of the implicit return of the last command (result of the test). 63 # NOTE: By requiring NIX_LOG_FD be set, we avoid dumping logging inside of nix-shell. 64 [[ -z ${NIX_LOG_FD-} ]] && return 0 65 66 # Use the function name of the caller, unless it is _callImplicitHook, in which case use the name of the hook. 67 local callerName="${FUNCNAME[1]}" 68 if [[ $callerName == "_callImplicitHook" ]]; then 69 callerName="${hookName:?}" 70 fi 71 printf "%s: %s\n" "$callerName" "$*" >&"$NIX_LOG_FD" 72} 73 74# Identical to nixLog, but additionally prefixed by the logLevel. 75# NOTE: This function is only every meant to be called from the nix*Log family of functions. 76_nixLogWithLevel() { 77 # Return a value explicitly instead of the implicit return of the last command (result of the test). 78 # NOTE: By requiring NIX_LOG_FD be set, we avoid dumping logging inside of nix-shell. 79 [[ -z ${NIX_LOG_FD-} || ${NIX_DEBUG:-0} -lt ${1:?} ]] && return 0 80 81 local logLevel 82 case "${1:?}" in 83 0) logLevel=ERROR ;; 84 1) logLevel=WARN ;; 85 2) logLevel=NOTICE ;; 86 3) logLevel=INFO ;; 87 4) logLevel=TALKATIVE ;; 88 5) logLevel=CHATTY ;; 89 6) logLevel=DEBUG ;; 90 7) logLevel=VOMIT ;; 91 *) 92 echo "_nixLogWithLevel: called with invalid log level: ${1:?}" >&"$NIX_LOG_FD" 93 return 1 94 ;; 95 esac 96 97 # Use the function name of the caller, unless it is _callImplicitHook, in which case use the name of the hook. 98 # NOTE: Our index into FUNCNAME is 2, not 1, because we are only ever to be called from the nix*Log family of 99 # functions, never directly. 100 local callerName="${FUNCNAME[2]}" 101 if [[ $callerName == "_callImplicitHook" ]]; then 102 callerName="${hookName:?}" 103 fi 104 105 # Use the function name of the caller's caller, since we should only every be invoked by nix*Log functions. 106 printf "%s: %s: %s\n" "$logLevel" "$callerName" "${2:?}" >&"$NIX_LOG_FD" 107} 108 109# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 110# Corresponds to `Verbosity::lvlError` in the Nix source. 111nixErrorLog() { 112 _nixLogWithLevel 0 "$*" 113} 114 115# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 116# Corresponds to `Verbosity::lvlWarn` in the Nix source. 117nixWarnLog() { 118 _nixLogWithLevel 1 "$*" 119} 120 121# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 122# Corresponds to `Verbosity::lvlNotice` in the Nix source. 123nixNoticeLog() { 124 _nixLogWithLevel 2 "$*" 125} 126 127# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 128# Corresponds to `Verbosity::lvlInfo` in the Nix source. 129nixInfoLog() { 130 _nixLogWithLevel 3 "$*" 131} 132 133# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 134# Corresponds to `Verbosity::lvlTalkative` in the Nix source. 135nixTalkativeLog() { 136 _nixLogWithLevel 4 "$*" 137} 138 139# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 140# Corresponds to `Verbosity::lvlChatty` in the Nix source. 141nixChattyLog() { 142 _nixLogWithLevel 5 "$*" 143} 144 145# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 146# Corresponds to `Verbosity::lvlDebug` in the Nix source. 147nixDebugLog() { 148 _nixLogWithLevel 6 "$*" 149} 150 151# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. 152# Corresponds to `Verbosity::lvlVomit` in the Nix source. 153nixVomitLog() { 154 _nixLogWithLevel 7 "$*" 155} 156 157# Log a hook, to be run before the hook is actually called. 158# logging for "implicit" hooks -- the ones specified directly 159# in derivation's arguments -- is done in _callImplicitHook instead. 160_logHook() { 161 # Fast path in case nixTalkativeLog is no-op. 162 if [[ -z ${NIX_LOG_FD-} ]]; then 163 return 164 fi 165 166 local hookKind="$1" 167 local hookExpr="$2" 168 shift 2 169 170 if declare -F "$hookExpr" > /dev/null 2>&1; then 171 nixTalkativeLog "calling '$hookKind' function hook '$hookExpr'" "$@" 172 elif type -p "$hookExpr" > /dev/null; then 173 nixTalkativeLog "sourcing '$hookKind' script hook '$hookExpr'" 174 elif [[ "$hookExpr" != "_callImplicitHook"* ]]; then 175 # Here we have a string hook to eval. 176 # Join lines onto one with literal \n characters unless NIX_DEBUG >= 5. 177 local exprToOutput 178 if [[ ${NIX_DEBUG:-0} -ge 5 ]]; then 179 exprToOutput="$hookExpr" 180 else 181 # We have `r'\n'.join([line.lstrip() for lines in text.split('\n')])` at home. 182 local hookExprLine 183 while IFS= read -r hookExprLine; do 184 # These lines often have indentation, 185 # so let's remove leading whitespace. 186 hookExprLine="${hookExprLine#"${hookExprLine%%[![:space:]]*}"}" 187 # If this line wasn't entirely whitespace, 188 # then add it to our output 189 if [[ -n "$hookExprLine" ]]; then 190 exprToOutput+="$hookExprLine\\n " 191 fi 192 done <<< "$hookExpr" 193 194 # And then remove the final, unnecessary, \n 195 exprToOutput="${exprToOutput%%\\n }" 196 fi 197 nixTalkativeLog "evaling '$hookKind' string hook '$exprToOutput'" 198 fi 199} 200 201###################################################################### 202# Hook handling. 203 204# Run all hooks with the specified name in the order in which they 205# were added, stopping if any fails (returns a non-zero exit 206# code). The hooks for <hookName> are the shell function or variable 207# <hookName>, and the values of the shell array ‘<hookName>Hooks’. 208runHook() { 209 local hookName="$1" 210 shift 211 local hooksSlice="${hookName%Hook}Hooks[@]" 212 213 local hook 214 # Hack around old bash being bad and thinking empty arrays are 215 # undefined. 216 for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do 217 _logHook "$hookName" "$hook" "$@" 218 _eval "$hook" "$@" 219 done 220 221 return 0 222} 223 224 225# Run all hooks with the specified name, until one succeeds (returns a 226# zero exit code). If none succeed, return a non-zero exit code. 227runOneHook() { 228 local hookName="$1" 229 shift 230 local hooksSlice="${hookName%Hook}Hooks[@]" 231 232 local hook ret=1 233 # Hack around old bash like above 234 for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do 235 _logHook "$hookName" "$hook" "$@" 236 if _eval "$hook" "$@"; then 237 ret=0 238 break 239 fi 240 done 241 242 return "$ret" 243} 244 245 246# Run the named hook, either by calling the function with that name or 247# by evaluating the variable with that name. This allows convenient 248# setting of hooks both from Nix expressions (as attributes / 249# environment variables) and from shell scripts (as functions). If you 250# want to allow multiple hooks, use runHook instead. 251_callImplicitHook() { 252 local def="$1" 253 local hookName="$2" 254 if declare -F "$hookName" > /dev/null; then 255 nixTalkativeLog "calling implicit '$hookName' function hook" 256 "$hookName" 257 elif type -p "$hookName" > /dev/null; then 258 nixTalkativeLog "sourcing implicit '$hookName' script hook" 259 source "$hookName" 260 elif [ -n "${!hookName:-}" ]; then 261 nixTalkativeLog "evaling implicit '$hookName' string hook" 262 eval "${!hookName}" 263 else 264 return "$def" 265 fi 266 # `_eval` expects hook to need nounset disable and leave it 267 # disabled anyways, so Ok to to delegate. The alternative of a 268 # return trap is no good because it would affect nested returns. 269} 270 271 272# A function wrapper around ‘eval’ that ensures that ‘return’ inside 273# hooks exits the hook, not the caller. Also will only pass args if 274# command can take them 275_eval() { 276 if declare -F "$1" > /dev/null 2>&1; then 277 "$@" # including args 278 else 279 eval "$1" 280 fi 281} 282 283 284###################################################################### 285# Logging. 286 287# Prints a command such that all word splits are unambiguous. We need 288# to split the command in three parts because the middle format string 289# will be, and must be, repeated for each argument. The first argument 290# goes before the ':' and is just for convenience. 291echoCmd() { 292 printf "%s:" "$1" 293 shift 294 printf ' %q' "$@" 295 echo 296} 297 298 299###################################################################### 300# Error handling. 301 302exitHandler() { 303 exitCode="$?" 304 set +e 305 306 if [ -n "${showBuildStats:-}" ]; then 307 read -r -d '' -a buildTimes < <(times) 308 echo "build times:" 309 echo "user time for the shell ${buildTimes[0]}" 310 echo "system time for the shell ${buildTimes[1]}" 311 echo "user time for all child processes ${buildTimes[2]}" 312 echo "system time for all child processes ${buildTimes[3]}" 313 fi 314 315 if (( "$exitCode" != 0 )); then 316 runHook failureHook 317 318 # If the builder had a non-zero exit code and 319 # $succeedOnFailure is set, create the file 320 # ‘$out/nix-support/failed’ to signal failure, and exit 321 # normally. Otherwise, return the original exit code. 322 if [ -n "${succeedOnFailure:-}" ]; then 323 echo "build failed with exit code $exitCode (ignored)" 324 mkdir -p "$out/nix-support" 325 printf "%s" "$exitCode" > "$out/nix-support/failed" 326 exit 0 327 fi 328 329 else 330 runHook exitHook 331 fi 332 333 return "$exitCode" 334} 335 336trap "exitHandler" EXIT 337 338 339###################################################################### 340# Helper functions. 341 342 343addToSearchPathWithCustomDelimiter() { 344 local delimiter="$1" 345 local varName="$2" 346 local dir="$3" 347 if [[ -d "$dir" && "${!varName:+${delimiter}${!varName}${delimiter}}" \ 348 != *"${delimiter}${dir}${delimiter}"* ]]; then 349 export "${varName}=${!varName:+${!varName}${delimiter}}${dir}" 350 fi 351} 352 353addToSearchPath() { 354 addToSearchPathWithCustomDelimiter ":" "$@" 355} 356 357# Prepend elements to variable "$1", which may come from an attr. 358# 359# This is useful in generic setup code, which must (for now) support 360# both derivations with and without __structuredAttrs true, so the 361# variable may be an array or a space-separated string. 362# 363# Expressions for individual packages should simply switch to array 364# syntax when they switch to setting __structuredAttrs = true. 365prependToVar() { 366 local -n nameref="$1" 367 local useArray type 368 369 if [ -n "$__structuredAttrs" ]; then 370 useArray=true 371 else 372 useArray=false 373 fi 374 375 # check if variable already exist and if it does then do extra checks 376 if type=$(declare -p "$1" 2> /dev/null); then 377 case "${type#* }" in 378 -A*) 379 echo "prependToVar(): ERROR: trying to use prependToVar on an associative array." >&2 380 return 1 ;; 381 -a*) 382 useArray=true ;; 383 *) 384 useArray=false ;; 385 esac 386 fi 387 388 shift 389 390 if $useArray; then 391 nameref=( "$@" ${nameref+"${nameref[@]}"} ) 392 else 393 nameref="$* ${nameref-}" 394 fi 395} 396 397# Same as above 398appendToVar() { 399 local -n nameref="$1" 400 local useArray type 401 402 if [ -n "$__structuredAttrs" ]; then 403 useArray=true 404 else 405 useArray=false 406 fi 407 408 # check if variable already exist and if it does then do extra checks 409 if type=$(declare -p "$1" 2> /dev/null); then 410 case "${type#* }" in 411 -A*) 412 echo "appendToVar(): ERROR: trying to use appendToVar on an associative array, use variable+=([\"X\"]=\"Y\") instead." >&2 413 return 1 ;; 414 -a*) 415 useArray=true ;; 416 *) 417 useArray=false ;; 418 esac 419 fi 420 421 shift 422 423 if $useArray; then 424 nameref=( ${nameref+"${nameref[@]}"} "$@" ) 425 else 426 nameref="${nameref-} $*" 427 fi 428} 429 430# Accumulate flags from the named variables $2+ into the indexed array $1. 431# 432# Arrays are simply concatenated, strings are split on whitespace. 433# Default values can be passed via name=default. 434concatTo() { 435 local - 436 set -o noglob 437 local -n targetref="$1"; shift 438 local arg default name type 439 for arg in "$@"; do 440 IFS="=" read -r name default <<< "$arg" 441 local -n nameref="$name" 442 if [[ -z "${nameref[*]}" && -n "$default" ]]; then 443 targetref+=( "$default" ) 444 elif type=$(declare -p "$name" 2> /dev/null); then 445 case "${type#* }" in 446 -A*) 447 echo "concatTo(): ERROR: trying to use concatTo on an associative array." >&2 448 return 1 ;; 449 -a*) 450 targetref+=( "${nameref[@]}" ) ;; 451 *) 452 if [[ "$name" = *"Array" ]]; then 453 nixErrorLog "concatTo(): $name is not declared as array, treating as a singleton. This will become an error in future" 454 # Reproduces https://github.com/NixOS/nixpkgs/pull/318614/files#diff-7c7ca80928136cfc73a02d5b28350bd900e331d6d304857053ffc9f7beaad576L359 455 targetref+=( ${nameref+"${nameref[@]}"} ) 456 else 457 # shellcheck disable=SC2206 458 targetref+=( ${nameref-} ) 459 fi 460 ;; 461 esac 462 fi 463 done 464} 465 466# Concatenate a list of strings ($2) with a separator ($1) between each element. 467# The list can be an indexed array of strings or a single string. A single string 468# is split on spaces and then concatenated with the separator. 469# 470# $ flags="lorem ipsum dolor sit amet" 471# $ concatStringsSep ";" flags 472# lorem;ipsum;dolor;sit;amet 473# 474# $ flags=("lorem ipsum" "dolor" "sit amet") 475# $ concatStringsSep ";" flags 476# lorem ipsum;dolor;sit amet 477# 478# Also supports multi-character separators; 479# $ flags=("lorem ipsum" "dolor" "sit amet") 480# $ concatStringsSep " and " flags 481# lorem ipsum and dolor and sit amet 482concatStringsSep() { 483 local sep="$1" 484 local name="$2" 485 local type oldifs 486 if type=$(declare -p "$name" 2> /dev/null); then 487 local -n nameref="$name" 488 case "${type#* }" in 489 -A*) 490 echo "concatStringsSep(): ERROR: trying to use concatStringsSep on an associative array." >&2 491 return 1 ;; 492 -a*) 493 # \036 is the "record separator" character. We assume that this will never need to be part of 494 # an argument string we create here. If anyone ever hits this limitation: Feel free to refactor. 495 # To avoid leaking an unescaped rs character when dumping the environment with nix, we use printf 496 # in a subshell. 497 local IFS="$(printf '\036')" ;; 498 *) 499 local IFS=" " ;; 500 501 esac 502 local ifs_separated="${nameref[*]}" 503 echo -n "${ifs_separated//"$IFS"/"$sep"}" 504 fi 505} 506 507# Add $1/lib* into rpaths. 508# The function is used in multiple-outputs.sh hook, 509# so it is defined here but tried after the hook. 510_addRpathPrefix() { 511 if [ "${NIX_NO_SELF_RPATH:-0}" != 1 ]; then 512 export NIX_LDFLAGS="-rpath $1/lib ${NIX_LDFLAGS-}" 513 fi 514} 515 516# Return success if the specified file is an ELF object. 517isELF() { 518 local fn="$1" 519 local fd 520 local magic 521 exec {fd}< "$fn" 522 read -r -n 4 -u "$fd" magic 523 exec {fd}<&- 524 if [ "$magic" = $'\177ELF' ]; then return 0; else return 1; fi 525} 526 527# Return success if the specified file is a Mach-O object. 528isMachO() { 529 local fn="$1" 530 local fd 531 local magic 532 exec {fd}< "$fn" 533 read -r -n 4 -u "$fd" magic 534 exec {fd}<&- 535 536 # nix uses 'declare -F' in get-env.sh to retrieve the loaded functions. 537 # If we use the $'string' syntax instead of 'echo -ne' then 'declare' will print the raw characters and break nix. 538 # See https://github.com/NixOS/nixpkgs/pull/138334 and https://github.com/NixOS/nix/issues/5262. 539 540 # https://opensource.apple.com/source/lldb/lldb-310.2.36/examples/python/mach_o.py.auto.html 541 if [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xcf") || "$magic" = $(echo -ne "\xcf\xfa\xed\xfe") ]]; then 542 # MH_MAGIC_64 || MH_CIGAM_64 543 return 0; 544 elif [[ "$magic" = $(echo -ne "\xfe\xed\xfa\xce") || "$magic" = $(echo -ne "\xce\xfa\xed\xfe") ]]; then 545 # MH_MAGIC || MH_CIGAM 546 return 0; 547 elif [[ "$magic" = $(echo -ne "\xca\xfe\xba\xbe") || "$magic" = $(echo -ne "\xbe\xba\xfe\xca") ]]; then 548 # FAT_MAGIC || FAT_CIGAM 549 return 0; 550 else 551 return 1; 552 fi 553} 554 555# Return success if the specified file is a script (i.e. starts with 556# "#!"). 557isScript() { 558 local fn="$1" 559 local fd 560 local magic 561 exec {fd}< "$fn" 562 read -r -n 2 -u "$fd" magic 563 exec {fd}<&- 564 if [[ "$magic" =~ \#! ]]; then return 0; else return 1; fi 565} 566 567# printf unfortunately will print a trailing newline regardless 568printLines() { 569 (( "$#" > 0 )) || return 0 570 printf '%s\n' "$@" 571} 572 573printWords() { 574 (( "$#" > 0 )) || return 0 575 printf '%s ' "$@" 576} 577 578###################################################################### 579# Initialisation. 580 581# If using structured attributes, export variables from `env` to the environment. 582# When not using structured attributes, those variables are already exported. 583if [[ -n $__structuredAttrs ]]; then 584 for envVar in "${!env[@]}"; do 585 declare -x "${envVar}=${env[${envVar}]}" 586 done 587fi 588 589 590# Set a fallback default value for SOURCE_DATE_EPOCH, used by some build tools 591# to provide a deterministic substitute for the "current" time. Note that 592# 315532800 = 1980-01-01 12:00:00. We use this date because python's wheel 593# implementation uses zip archive and zip does not support dates going back to 594# 1970. 595export SOURCE_DATE_EPOCH 596: "${SOURCE_DATE_EPOCH:=315532800}" 597 598 599# Wildcard expansions that don't match should expand to an empty list. 600# This ensures that, for instance, "for i in *; do ...; done" does the 601# right thing. 602shopt -s nullglob 603 604 605# Set up the initial path. 606PATH= 607HOST_PATH= 608for i in $initialPath; do 609 if [ "$i" = / ]; then i=; fi 610 addToSearchPath PATH "$i/bin" 611 612 # For backward compatibility, we add initial path to HOST_PATH so 613 # it can be used in auto patch-shebangs. Unfortunately this will 614 # not work with cross compilation. 615 if [ -z "${strictDeps-}" ]; then 616 addToSearchPath HOST_PATH "$i/bin" 617 fi 618done 619 620unset i 621 622nixWarnLog "initial path: $PATH" 623 624# Check that the pre-hook initialised SHELL. 625if [ -z "${SHELL:-}" ]; then echo "SHELL not set"; exit 1; fi 626BASH="$SHELL" 627export CONFIG_SHELL="$SHELL" 628 629 630# Execute the pre-hook. 631if [ -z "${shell:-}" ]; then export shell="$SHELL"; fi 632runHook preHook 633 634 635# Allow the caller to augment buildInputs (it's not always possible to 636# do this before the call to setup.sh, since the PATH is empty at that 637# point; here we have a basic Unix environment). 638runHook addInputsHook 639 640 641# Package accumulators 642 643declare -a pkgsBuildBuild pkgsBuildHost pkgsBuildTarget 644declare -a pkgsHostHost pkgsHostTarget 645declare -a pkgsTargetTarget 646 647declare -a pkgBuildAccumVars=(pkgsBuildBuild pkgsBuildHost pkgsBuildTarget) 648declare -a pkgHostAccumVars=(pkgsHostHost pkgsHostTarget) 649declare -a pkgTargetAccumVars=(pkgsTargetTarget) 650 651declare -a pkgAccumVarVars=(pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars) 652 653 654# Hooks 655 656declare -a envBuildBuildHooks envBuildHostHooks envBuildTargetHooks 657declare -a envHostHostHooks envHostTargetHooks 658declare -a envTargetTargetHooks 659 660declare -a pkgBuildHookVars=(envBuildBuildHook envBuildHostHook envBuildTargetHook) 661declare -a pkgHostHookVars=(envHostHostHook envHostTargetHook) 662declare -a pkgTargetHookVars=(envTargetTargetHook) 663 664declare -a pkgHookVarVars=(pkgBuildHookVars pkgHostHookVars pkgTargetHookVars) 665 666# those variables are declared here, since where and if they are used varies 667declare -a preFixupHooks fixupOutputHooks preConfigureHooks postFixupHooks postUnpackHooks unpackCmdHooks 668 669# Add env hooks for all sorts of deps with the specified host offset. 670addEnvHooks() { 671 local depHostOffset="$1" 672 shift 673 local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]" 674 local pkgHookVar 675 for pkgHookVar in "${!pkgHookVarsSlice}"; do 676 eval "${pkgHookVar}s"'+=("$@")' 677 done 678} 679 680 681# Propagated dep files 682 683declare -a propagatedBuildDepFiles=( 684 propagated-build-build-deps 685 propagated-native-build-inputs # Legacy name for back-compat 686 propagated-build-target-deps 687) 688declare -a propagatedHostDepFiles=( 689 propagated-host-host-deps 690 propagated-build-inputs # Legacy name for back-compat 691) 692declare -a propagatedTargetDepFiles=( 693 propagated-target-target-deps 694) 695declare -a propagatedDepFilesVars=( 696 propagatedBuildDepFiles 697 propagatedHostDepFiles 698 propagatedTargetDepFiles 699) 700 701# Platform offsets: build = -1, host = 0, target = 1 702declare -a allPlatOffsets=(-1 0 1) 703 704 705# Mutually-recursively find all build inputs. See the dependency section of the 706# stdenv chapter of the Nixpkgs manual for the specification this algorithm 707# implements. 708findInputs() { 709 local -r pkg="$1" 710 local -r hostOffset="$2" 711 local -r targetOffset="$3" 712 713 # Sanity check 714 (( hostOffset <= targetOffset )) || exit 1 715 716 # shellcheck disable=SC1087 717 local varVar="${pkgAccumVarVars[hostOffset + 1]}" 718 # shellcheck disable=SC1087 719 local varRef="$varVar[$((targetOffset - hostOffset))]" 720 local var="${!varRef}" 721 unset -v varVar varRef 722 723 # TODO(@Ericson2314): Restore using associative array once Darwin 724 # nix-shell doesn't use impure bash. This should replace the O(n) 725 # case with an O(1) hash map lookup, assuming bash is implemented 726 # well :D. 727 # shellcheck disable=SC1087 728 local varSlice="$var[*]" 729 # ${..-} to hack around old bash empty array problem 730 case " ${!varSlice-} " in 731 *" $pkg "*) return 0 ;; 732 esac 733 unset -v varSlice 734 735 eval "$var"'+=("$pkg")' 736 737 if ! [ -e "$pkg" ]; then 738 echo "build input $pkg does not exist" >&2 739 exit 1 740 fi 741 742 # The current package's host and target offset together 743 # provide a <=-preserving homomorphism from the relative 744 # offsets to current offset 745 function mapOffset() { 746 local -r inputOffset="$1" 747 local -n outputOffset="$2" 748 if (( inputOffset <= 0 )); then 749 outputOffset=$((inputOffset + hostOffset)) 750 else 751 outputOffset=$((inputOffset - 1 + targetOffset)) 752 fi 753 } 754 755 # Host offset relative to that of the package whose immediate 756 # dependencies we are currently exploring. 757 local relHostOffset 758 for relHostOffset in "${allPlatOffsets[@]}"; do 759 # `+ 1` so we start at 0 for valid index 760 local files="${propagatedDepFilesVars[relHostOffset + 1]}" 761 762 # Host offset relative to the package currently being 763 # built---as absolute an offset as will be used. 764 local hostOffsetNext 765 mapOffset "$relHostOffset" hostOffsetNext 766 767 # Ensure we're in bounds relative to the package currently 768 # being built. 769 (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue 770 771 # Target offset relative to the *host* offset of the package 772 # whose immediate dependencies we are currently exploring. 773 local relTargetOffset 774 for relTargetOffset in "${allPlatOffsets[@]}"; do 775 (( "$relHostOffset" <= "$relTargetOffset" )) || continue 776 777 local fileRef="${files}[$relTargetOffset - $relHostOffset]" 778 local file="${!fileRef}" 779 unset -v fileRef 780 781 # Target offset relative to the package currently being 782 # built. 783 local targetOffsetNext 784 mapOffset "$relTargetOffset" targetOffsetNext 785 786 # Once again, ensure we're in bounds relative to the 787 # package currently being built. 788 (( -1 <= hostOffsetNext && hostOffsetNext <= 1 )) || continue 789 790 [[ -f "$pkg/nix-support/$file" ]] || continue 791 792 local pkgNext 793 read -r -d '' pkgNext < "$pkg/nix-support/$file" || true 794 for pkgNext in $pkgNext; do 795 findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext" 796 done 797 done 798 done 799} 800 801# The way we handle deps* and *Inputs works with structured attrs 802# either enabled or disabled. For this it's convenient that the items 803# in each list must be store paths, and therefore space-free. 804 805# Make sure all are at least defined as empty 806: "${depsBuildBuild=}" "${depsBuildBuildPropagated=}" 807: "${nativeBuildInputs=}" "${propagatedNativeBuildInputs=}" "${defaultNativeBuildInputs=}" 808: "${depsBuildTarget=}" "${depsBuildTargetPropagated=}" 809: "${depsHostHost=}" "${depsHostHostPropagated=}" 810: "${buildInputs=}" "${propagatedBuildInputs=}" "${defaultBuildInputs=}" 811: "${depsTargetTarget=}" "${depsTargetTargetPropagated=}" 812 813for pkg in ${depsBuildBuild[@]} ${depsBuildBuildPropagated[@]}; do 814 findInputs "$pkg" -1 -1 815done 816for pkg in ${nativeBuildInputs[@]} ${propagatedNativeBuildInputs[@]}; do 817 findInputs "$pkg" -1 0 818done 819for pkg in ${depsBuildTarget[@]} ${depsBuildTargetPropagated[@]}; do 820 findInputs "$pkg" -1 1 821done 822for pkg in ${depsHostHost[@]} ${depsHostHostPropagated[@]}; do 823 findInputs "$pkg" 0 0 824done 825for pkg in ${buildInputs[@]} ${propagatedBuildInputs[@]} ; do 826 findInputs "$pkg" 0 1 827done 828for pkg in ${depsTargetTarget[@]} ${depsTargetTargetPropagated[@]}; do 829 findInputs "$pkg" 1 1 830done 831# Default inputs must be processed last 832for pkg in ${defaultNativeBuildInputs[@]}; do 833 findInputs "$pkg" -1 0 834done 835for pkg in ${defaultBuildInputs[@]}; do 836 findInputs "$pkg" 0 1 837done 838 839# Add package to the future PATH and run setup hooks 840activatePackage() { 841 local pkg="$1" 842 local -r hostOffset="$2" 843 local -r targetOffset="$3" 844 845 # Sanity check 846 (( hostOffset <= targetOffset )) || exit 1 847 848 if [ -f "$pkg" ]; then 849 nixTalkativeLog "sourcing setup hook '$pkg'" 850 source "$pkg" 851 fi 852 853 # Only dependencies whose host platform is guaranteed to match the 854 # build platform are included here. That would be `depsBuild*`, 855 # and legacy `nativeBuildInputs`, in general. If we aren't cross 856 # compiling, however, everything can be put on the PATH. To ease 857 # the transition, we do include everything in that case. 858 # 859 # TODO(@Ericson2314): Don't special-case native compilation 860 if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then 861 addToSearchPath _PATH "$pkg/bin" 862 fi 863 864 if (( hostOffset <= -1 )); then 865 addToSearchPath _XDG_DATA_DIRS "$pkg/share" 866 fi 867 868 if [[ "$hostOffset" -eq 0 && -d "$pkg/bin" ]]; then 869 addToSearchPath _HOST_PATH "$pkg/bin" 870 fi 871 872 if [[ -f "$pkg/nix-support/setup-hook" ]]; then 873 nixTalkativeLog "sourcing setup hook '$pkg/nix-support/setup-hook'" 874 source "$pkg/nix-support/setup-hook" 875 fi 876} 877 878_activatePkgs() { 879 local hostOffset targetOffset 880 local pkg 881 882 for hostOffset in "${allPlatOffsets[@]}"; do 883 local pkgsVar="${pkgAccumVarVars[hostOffset + 1]}" 884 for targetOffset in "${allPlatOffsets[@]}"; do 885 (( hostOffset <= targetOffset )) || continue 886 local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]" 887 local pkgsSlice="${!pkgsRef}[@]" 888 for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do 889 activatePackage "$pkg" "$hostOffset" "$targetOffset" 890 done 891 done 892 done 893} 894 895# Run the package setup hooks and build _PATH 896_activatePkgs 897 898# Set the relevant environment variables to point to the build inputs 899# found above. 900# 901# These `depOffset`s, beyond indexing the arrays, also tell the env 902# hook what sort of dependency (ignoring propagatedness) is being 903# passed to the env hook. In a real language, we'd append a closure 904# with this information to the relevant env hook array, but bash 905# doesn't have closures, so it's easier to just pass this in. 906_addToEnv() { 907 local depHostOffset depTargetOffset 908 local pkg 909 910 for depHostOffset in "${allPlatOffsets[@]}"; do 911 local hookVar="${pkgHookVarVars[depHostOffset + 1]}" 912 local pkgsVar="${pkgAccumVarVars[depHostOffset + 1]}" 913 for depTargetOffset in "${allPlatOffsets[@]}"; do 914 (( depHostOffset <= depTargetOffset )) || continue 915 local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]" 916 if [[ -z "${strictDeps-}" ]]; then 917 918 # Keep track of which packages we have visited before. 919 local visitedPkgs="" 920 921 # Apply environment hooks to all packages during native 922 # compilation to ease the transition. 923 # 924 # TODO(@Ericson2314): Don't special-case native compilation 925 for pkg in \ 926 "${pkgsBuildBuild[@]}" \ 927 "${pkgsBuildHost[@]}" \ 928 "${pkgsBuildTarget[@]}" \ 929 "${pkgsHostHost[@]}" \ 930 "${pkgsHostTarget[@]}" \ 931 "${pkgsTargetTarget[@]}" 932 do 933 if [[ "$visitedPkgs" = *"$pkg"* ]]; then 934 continue 935 fi 936 runHook "${!hookRef}" "$pkg" 937 visitedPkgs+=" $pkg" 938 done 939 else 940 local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]" 941 local pkgsSlice="${!pkgsRef}[@]" 942 for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do 943 runHook "${!hookRef}" "$pkg" 944 done 945 fi 946 done 947 done 948} 949 950# Run the package-specific hooks set by the setup-hook scripts. 951_addToEnv 952 953 954# Unset setup-specific declared variables 955unset allPlatOffsets 956unset pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars pkgAccumVarVars 957unset pkgBuildHookVars pkgHostHookVars pkgTargetHookVars pkgHookVarVars 958unset propagatedDepFilesVars 959 960 961_addRpathPrefix "$out" 962 963 964# Set the TZ (timezone) environment variable, otherwise commands like 965# `date' will complain (e.g., `Tue Mar 9 10:01:47 Local time zone must 966# be set--see zic manual page 2004'). 967export TZ=UTC 968 969 970# Set the prefix. This is generally $out, but it can be overriden, 971# for instance if we just want to perform a test build/install to a 972# temporary location and write a build report to $out. 973if [ -z "${prefix:-}" ]; then 974 prefix="$out"; 975fi 976 977if [ "${useTempPrefix:-}" = 1 ]; then 978 prefix="$NIX_BUILD_TOP/tmp_prefix"; 979fi 980 981 982PATH="${_PATH-}${_PATH:+${PATH:+:}}$PATH" 983HOST_PATH="${_HOST_PATH-}${_HOST_PATH:+${HOST_PATH:+:}}$HOST_PATH" 984export XDG_DATA_DIRS="${_XDG_DATA_DIRS-}${_XDG_DATA_DIRS:+${XDG_DATA_DIRS:+:}}${XDG_DATA_DIRS-}" 985 986nixWarnLog "final path: $PATH" 987nixWarnLog "final host path: $HOST_PATH" 988nixWarnLog "final data dirs: $XDG_DATA_DIRS" 989 990unset _PATH 991unset _HOST_PATH 992unset _XDG_DATA_DIRS 993 994 995# Normalize the NIX_BUILD_CORES variable. The value might be 0, which 996# means that we're supposed to try and auto-detect the number of 997# available CPU cores at run-time. 998 999NIX_BUILD_CORES="${NIX_BUILD_CORES:-1}" 1000if ((NIX_BUILD_CORES <= 0)); then 1001 guess=$(nproc 2>/dev/null || true) 1002 ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess)) 1003fi 1004export NIX_BUILD_CORES 1005 1006 1007# Prevent SSL libraries from using certificates in /etc/ssl, unless set explicitly. 1008# Leave it in impure shells for convenience. 1009if [[ -z "${NIX_SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]; then 1010 export NIX_SSL_CERT_FILE=/no-cert-file.crt 1011fi 1012# Another variant left for compatibility. 1013if [[ -z "${SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]; then 1014 export SSL_CERT_FILE=/no-cert-file.crt 1015fi 1016 1017 1018###################################################################### 1019# Textual substitution functions. 1020 1021# only log once, due to max logging limit on hydra 1022_substituteStream_has_warned_replace_deprecation=false 1023 1024substituteStream() { 1025 local var=$1 1026 local description=$2 1027 shift 2 1028 1029 while (( "$#" )); do 1030 local replace_mode="$1" 1031 case "$1" in 1032 --replace) 1033 # deprecated 2023-11-22 1034 # this will either get removed, or switch to the behaviour of --replace-fail in the future 1035 if ! "$_substituteStream_has_warned_replace_deprecation"; then 1036 echo "substituteStream() in derivation $name: WARNING: '--replace' is deprecated, use --replace-{fail,warn,quiet}. ($description)" >&2 1037 _substituteStream_has_warned_replace_deprecation=true 1038 fi 1039 replace_mode='--replace-warn' 1040 ;& 1041 --replace-quiet|--replace-warn|--replace-fail) 1042 pattern="$2" 1043 replacement="$3" 1044 shift 3 1045 if ! [[ "${!var}" == *"$pattern"* ]]; then 1046 if [ "$replace_mode" == --replace-warn ]; then 1047 printf "substituteStream() in derivation $name: WARNING: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2 1048 elif [ "$replace_mode" == --replace-fail ]; then 1049 printf "substituteStream() in derivation $name: ERROR: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2 1050 return 1 1051 fi 1052 fi 1053 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' 1054 ;; 1055 1056 --subst-var) 1057 local varName="$2" 1058 shift 2 1059 # check if the used nix attribute name is a valid bash name 1060 if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then 1061 echo "substituteStream() in derivation $name: ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2 1062 return 1 1063 fi 1064 if [ -z ${!varName+x} ]; then 1065 echo "substituteStream() in derivation $name: ERROR: variable \$$varName is unset" >&2 1066 return 1 1067 fi 1068 pattern="@$varName@" 1069 replacement="${!varName}" 1070 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' 1071 ;; 1072 1073 --subst-var-by) 1074 pattern="@$2@" 1075 replacement="$3" 1076 eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' 1077 shift 3 1078 ;; 1079 1080 *) 1081 echo "substituteStream() in derivation $name: ERROR: Invalid command line argument: $1" >&2 1082 return 1 1083 ;; 1084 esac 1085 done 1086 1087 printf "%s" "${!var}" 1088} 1089 1090# put the content of a file in a variable 1091# fail loudly if provided with a binary (containing null bytes) 1092consumeEntire() { 1093 # read returns non-0 on EOF, so we want read to fail 1094 if IFS='' read -r -d '' "$1" ; then 1095 echo "consumeEntire(): ERROR: Input null bytes, won't process" >&2 1096 return 1 1097 fi 1098} 1099 1100substitute() { 1101 local input="$1" 1102 local output="$2" 1103 shift 2 1104 1105 if [ ! -f "$input" ]; then 1106 echo "substitute(): ERROR: file '$input' does not exist" >&2 1107 return 1 1108 fi 1109 1110 local content 1111 consumeEntire content < "$input" 1112 1113 if [ -e "$output" ]; then chmod +w "$output"; fi 1114 substituteStream content "file '$input'" "$@" > "$output" 1115} 1116 1117substituteInPlace() { 1118 local -a fileNames=() 1119 for arg in "$@"; do 1120 if [[ "$arg" = "--"* ]]; then 1121 break 1122 fi 1123 fileNames+=("$arg") 1124 shift 1125 done 1126 if ! [[ "${#fileNames[@]}" -gt 0 ]]; then 1127 echo >&2 "substituteInPlace called without any files to operate on (files must come before options!)" 1128 return 1 1129 fi 1130 1131 for file in "${fileNames[@]}"; do 1132 substitute "$file" "$file" "$@" 1133 done 1134} 1135 1136_allFlags() { 1137 # Export some local variables for the `awk` below so some substitutions (such as name) 1138 # don't have to be in the env attrset when `__structuredAttrs` is enabled. 1139 export system pname name version 1140 while IFS='' read -r varName; do 1141 nixTalkativeLog "@${varName}@ -> ${!varName}" 1142 args+=("--subst-var" "$varName") 1143 done < <(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }') 1144} 1145 1146substituteAllStream() { 1147 local -a args=() 1148 _allFlags 1149 1150 substituteStream "$1" "$2" "${args[@]}" 1151} 1152 1153# Substitute all environment variables that start with a lowercase character and 1154# are valid Bash names. 1155substituteAll() { 1156 local input="$1" 1157 local output="$2" 1158 1159 local -a args=() 1160 _allFlags 1161 1162 substitute "$input" "$output" "${args[@]}" 1163} 1164 1165 1166substituteAllInPlace() { 1167 local fileName="$1" 1168 shift 1169 substituteAll "$fileName" "$fileName" "$@" 1170} 1171 1172 1173###################################################################### 1174# What follows is the generic builder. 1175 1176 1177# This function is useful for debugging broken Nix builds. It dumps 1178# all environment variables to a file `env-vars' in the build 1179# directory. If the build fails and the `-K' option is used, you can 1180# then go to the build directory and source in `env-vars' to reproduce 1181# the environment used for building. 1182dumpVars() { 1183 if [ "${noDumpEnvVars:-0}" != 1 ]; then 1184 # Don't use `install` here to prevent executing a process each time. 1185 1186 # Set umask to create env-vars file with 0600 permissions (owner read/write only) 1187 local old_umask 1188 old_umask=$(umask) 1189 umask 0077 1190 1191 # Dump all environment variables to the env-vars file 1192 export 2>/dev/null > "$NIX_BUILD_TOP/env-vars" 1193 1194 # Restore original umask 1195 umask "$old_umask" 1196 fi 1197} 1198 1199 1200# Utility function: echo the base name of the given path, with the 1201# prefix `HASH-' removed, if present. 1202stripHash() { 1203 local strippedName casematchOpt=0 1204 # On separate line for `set -e` 1205 strippedName="$(basename -- "$1")" 1206 shopt -q nocasematch && casematchOpt=1 1207 shopt -u nocasematch 1208 if [[ "$strippedName" =~ ^[a-z0-9]{32}- ]]; then 1209 echo "${strippedName:33}" 1210 else 1211 echo "$strippedName" 1212 fi 1213 if (( casematchOpt )); then shopt -s nocasematch; fi 1214} 1215 1216 1217recordPropagatedDependencies() { 1218 # Propagate dependencies into the development output. 1219 declare -ra flatVars=( 1220 # Build 1221 depsBuildBuildPropagated 1222 propagatedNativeBuildInputs 1223 depsBuildTargetPropagated 1224 # Host 1225 depsHostHostPropagated 1226 propagatedBuildInputs 1227 # Target 1228 depsTargetTargetPropagated 1229 ) 1230 declare -ra flatFiles=( 1231 "${propagatedBuildDepFiles[@]}" 1232 "${propagatedHostDepFiles[@]}" 1233 "${propagatedTargetDepFiles[@]}" 1234 ) 1235 1236 local propagatedInputsIndex 1237 for propagatedInputsIndex in "${!flatVars[@]}"; do 1238 local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]" 1239 local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}" 1240 1241 [[ "${!propagatedInputsSlice}" ]] || continue 1242 1243 mkdir -p "${!outputDev}/nix-support" 1244 # shellcheck disable=SC2086 1245 printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile" 1246 done 1247} 1248 1249 1250unpackCmdHooks+=(_defaultUnpack) 1251_defaultUnpack() { 1252 local fn="$1" 1253 local destination 1254 1255 if [ -d "$fn" ]; then 1256 1257 destination="$(stripHash "$fn")" 1258 1259 if [ -e "$destination" ]; then 1260 echo "Cannot copy $fn to $destination: destination already exists!" 1261 echo "Did you specify two \"srcs\" with the same \"name\"?" 1262 return 1 1263 fi 1264 1265 # We can't preserve hardlinks because they may have been 1266 # introduced by store optimization, which might break things 1267 # in the build. 1268 cp -r --preserve=timestamps --reflink=auto -- "$fn" "$destination" 1269 1270 else 1271 1272 case "$fn" in 1273 *.tar.xz | *.tar.lzma | *.txz) 1274 # Don't rely on tar knowing about .xz. 1275 # Additionally, we have multiple different xz binaries with different feature sets in different 1276 # stages. The XZ_OPT env var is only used by the full "XZ utils" implementation, which supports 1277 # the --threads (-T) flag. This allows us to enable multithreaded decompression exclusively on 1278 # that implementation, without the use of complex bash conditionals and checks. 1279 # Since tar does not control the decompression, we need to 1280 # disregard the error code from the xz invocation. Otherwise, 1281 # it can happen that tar exits earlier, causing xz to fail 1282 # from a SIGPIPE. 1283 (XZ_OPT="--threads=$NIX_BUILD_CORES" xz -d < "$fn"; true) | tar xf - --mode=+w --warning=no-timestamp 1284 ;; 1285 *.tar | *.tar.* | *.tgz | *.tbz2 | *.tbz) 1286 # GNU tar can automatically select the decompression method 1287 # (info "(tar) gzip"). 1288 tar xf "$fn" --mode=+w --warning=no-timestamp 1289 ;; 1290 *) 1291 return 1 1292 ;; 1293 esac 1294 1295 fi 1296} 1297 1298 1299unpackFile() { 1300 curSrc="$1" 1301 echo "unpacking source archive $curSrc" 1302 if ! runOneHook unpackCmd "$curSrc"; then 1303 echo "do not know how to unpack source archive $curSrc" 1304 exit 1 1305 fi 1306} 1307 1308 1309unpackPhase() { 1310 runHook preUnpack 1311 1312 if [ -z "${srcs:-}" ]; then 1313 if [ -z "${src:-}" ]; then 1314 # shellcheck disable=SC2016 1315 echo 'variable $src or $srcs should point to the source' 1316 exit 1 1317 fi 1318 srcs="$src" 1319 fi 1320 1321 local -a srcsArray 1322 concatTo srcsArray srcs 1323 1324 # To determine the source directory created by unpacking the 1325 # source archives, we record the contents of the current 1326 # directory, then look below which directory got added. Yeah, 1327 # it's rather hacky. 1328 local dirsBefore="" 1329 for i in *; do 1330 if [ -d "$i" ]; then 1331 dirsBefore="$dirsBefore $i " 1332 fi 1333 done 1334 1335 # Unpack all source archives. 1336 for i in "${srcsArray[@]}"; do 1337 unpackFile "$i" 1338 done 1339 1340 # Find the source directory. 1341 1342 # set to empty if unset 1343 : "${sourceRoot=}" 1344 1345 if [ -n "${setSourceRoot:-}" ]; then 1346 runOneHook setSourceRoot 1347 elif [ -z "$sourceRoot" ]; then 1348 for i in *; do 1349 if [ -d "$i" ]; then 1350 case $dirsBefore in 1351 *\ $i\ *) 1352 ;; 1353 *) 1354 if [ -n "$sourceRoot" ]; then 1355 echo "unpacker produced multiple directories" 1356 exit 1 1357 fi 1358 sourceRoot="$i" 1359 ;; 1360 esac 1361 fi 1362 done 1363 fi 1364 1365 if [ -z "$sourceRoot" ]; then 1366 echo "unpacker appears to have produced no directories" 1367 exit 1 1368 fi 1369 1370 echo "source root is $sourceRoot" 1371 1372 # By default, add write permission to the sources. This is often 1373 # necessary when sources have been copied from other store 1374 # locations. 1375 if [ "${dontMakeSourcesWritable:-0}" != 1 ]; then 1376 chmod -R u+w -- "$sourceRoot" 1377 fi 1378 1379 runHook postUnpack 1380} 1381 1382 1383patchPhase() { 1384 runHook prePatch 1385 1386 local -a patchesArray 1387 concatTo patchesArray patches 1388 1389 local -a flagsArray 1390 concatTo flagsArray patchFlags=-p1 1391 1392 for i in "${patchesArray[@]}"; do 1393 echo "applying patch $i" 1394 local uncompress=cat 1395 case "$i" in 1396 *.gz) 1397 uncompress="gzip -d" 1398 ;; 1399 *.bz2) 1400 uncompress="bzip2 -d" 1401 ;; 1402 *.xz) 1403 uncompress="xz -d" 1404 ;; 1405 *.lzma) 1406 uncompress="lzma -d" 1407 ;; 1408 esac 1409 1410 # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.) 1411 # shellcheck disable=SC2086 1412 $uncompress < "$i" 2>&1 | patch "${flagsArray[@]}" 1413 done 1414 1415 runHook postPatch 1416} 1417 1418 1419fixLibtool() { 1420 local search_path 1421 for flag in $NIX_LDFLAGS; do 1422 case $flag in 1423 -L*) 1424 search_path+=" ${flag#-L}" 1425 ;; 1426 esac 1427 done 1428 1429 sed -i "$1" \ 1430 -e "s^eval \(sys_lib_search_path=\).*^\1'${search_path:-}'^" \ 1431 -e 's^eval sys_lib_.+search_path=.*^^' 1432} 1433 1434 1435configurePhase() { 1436 runHook preConfigure 1437 1438 # set to empty if unset 1439 : "${configureScript=}" 1440 1441 if [[ -z "$configureScript" && -x ./configure ]]; then 1442 configureScript=./configure 1443 fi 1444 1445 if [ -z "${dontFixLibtool:-}" ]; then 1446 export lt_cv_deplibs_check_method="${lt_cv_deplibs_check_method-pass_all}" 1447 local i 1448 find . -iname "ltmain.sh" -print0 | while IFS='' read -r -d '' i; do 1449 echo "fixing libtool script $i" 1450 fixLibtool "$i" 1451 done 1452 1453 # replace `/usr/bin/file` with `file` in any `configure` 1454 # scripts with vendored libtool code. Preserve mtimes to 1455 # prevent some packages (e.g. libidn2) from spontaneously 1456 # autoreconf'ing themselves 1457 CONFIGURE_MTIME_REFERENCE=$(mktemp configure.mtime.reference.XXXXXX) 1458 find . \ 1459 -executable \ 1460 -type f \ 1461 -name configure \ 1462 -exec grep -l 'GNU Libtool is free software; you can redistribute it and/or modify' {} \; \ 1463 -exec touch -r {} "$CONFIGURE_MTIME_REFERENCE" \; \ 1464 -exec sed -i s_/usr/bin/file_file_g {} \; \ 1465 -exec touch -r "$CONFIGURE_MTIME_REFERENCE" {} \; 1466 rm -f "$CONFIGURE_MTIME_REFERENCE" 1467 fi 1468 1469 if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then 1470 prependToVar configureFlags "${prefixKey:---prefix=}$prefix" 1471 fi 1472 1473 if [[ -f "$configureScript" ]]; then 1474 # Add --disable-dependency-tracking to speed up some builds. 1475 if [ -z "${dontAddDisableDepTrack:-}" ]; then 1476 if grep -q dependency-tracking "$configureScript"; then 1477 prependToVar configureFlags --disable-dependency-tracking 1478 fi 1479 fi 1480 1481 # By default, disable static builds. 1482 if [ -z "${dontDisableStatic:-}" ]; then 1483 if grep -q enable-static "$configureScript"; then 1484 prependToVar configureFlags --disable-static 1485 fi 1486 fi 1487 1488 if [ -z "${dontPatchShebangsInConfigure:-}" ]; then 1489 patchShebangs --build "$configureScript" 1490 fi 1491 fi 1492 1493 if [ -n "$configureScript" ]; then 1494 local -a flagsArray 1495 concatTo flagsArray configureFlags configureFlagsArray 1496 1497 echoCmd 'configure flags' "${flagsArray[@]}" 1498 # shellcheck disable=SC2086 1499 $configureScript "${flagsArray[@]}" 1500 unset flagsArray 1501 else 1502 echo "no configure script, doing nothing" 1503 fi 1504 1505 runHook postConfigure 1506} 1507 1508 1509buildPhase() { 1510 runHook preBuild 1511 1512 if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then 1513 echo "no Makefile or custom buildPhase, doing nothing" 1514 else 1515 foundMakefile=1 1516 1517 # shellcheck disable=SC2086 1518 local flagsArray=( 1519 ${enableParallelBuilding:+-j${NIX_BUILD_CORES}} 1520 SHELL="$SHELL" 1521 ) 1522 concatTo flagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray 1523 1524 echoCmd 'build flags' "${flagsArray[@]}" 1525 make ${makefile:+-f $makefile} "${flagsArray[@]}" 1526 unset flagsArray 1527 fi 1528 1529 runHook postBuild 1530} 1531 1532 1533checkPhase() { 1534 runHook preCheck 1535 1536 if [[ -z "${foundMakefile:-}" ]]; then 1537 echo "no Makefile or custom checkPhase, doing nothing" 1538 runHook postCheck 1539 return 1540 fi 1541 1542 if [[ -z "${checkTarget:-}" ]]; then 1543 #TODO(@oxij): should flagsArray influence make -n? 1544 if make -n ${makefile:+-f $makefile} check >/dev/null 2>&1; then 1545 checkTarget="check" 1546 elif make -n ${makefile:+-f $makefile} test >/dev/null 2>&1; then 1547 checkTarget="test" 1548 fi 1549 fi 1550 1551 if [[ -z "${checkTarget:-}" ]]; then 1552 echo "no check/test target in ${makefile:-Makefile}, doing nothing" 1553 else 1554 # Old bash empty array hack 1555 # shellcheck disable=SC2086 1556 local flagsArray=( 1557 ${enableParallelChecking:+-j${NIX_BUILD_CORES}} 1558 SHELL="$SHELL" 1559 ) 1560 1561 concatTo flagsArray makeFlags makeFlagsArray checkFlags=VERBOSE=y checkFlagsArray checkTarget 1562 1563 echoCmd 'check flags' "${flagsArray[@]}" 1564 make ${makefile:+-f $makefile} "${flagsArray[@]}" 1565 1566 unset flagsArray 1567 fi 1568 1569 runHook postCheck 1570} 1571 1572 1573installPhase() { 1574 runHook preInstall 1575 1576 # Dont reuse 'foundMakefile' set in buildPhase, a makefile may have been created in buildPhase 1577 if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then 1578 echo "no Makefile or custom installPhase, doing nothing" 1579 runHook postInstall 1580 return 1581 else 1582 foundMakefile=1 1583 fi 1584 1585 if [ -n "$prefix" ]; then 1586 mkdir -p "$prefix" 1587 fi 1588 1589 # shellcheck disable=SC2086 1590 local flagsArray=( 1591 ${enableParallelInstalling:+-j${NIX_BUILD_CORES}} 1592 SHELL="$SHELL" 1593 ) 1594 1595 concatTo flagsArray makeFlags makeFlagsArray installFlags installFlagsArray installTargets=install 1596 1597 echoCmd 'install flags' "${flagsArray[@]}" 1598 make ${makefile:+-f $makefile} "${flagsArray[@]}" 1599 unset flagsArray 1600 1601 runHook postInstall 1602} 1603 1604 1605# The fixup phase performs generic, package-independent stuff, like 1606# stripping binaries, running patchelf and setting 1607# propagated-build-inputs. 1608fixupPhase() { 1609 # Make sure everything is writable so "strip" et al. work. 1610 local output 1611 for output in $(getAllOutputNames); do 1612 # for set*id bits see #300635 1613 if [ -e "${!output}" ]; then chmod -R u+w,u-s,g-s "${!output}"; fi 1614 done 1615 1616 runHook preFixup 1617 1618 # Apply fixup to each output. 1619 local output 1620 for output in $(getAllOutputNames); do 1621 prefix="${!output}" runHook fixupOutput 1622 done 1623 1624 1625 # record propagated dependencies & setup hook into the development output. 1626 recordPropagatedDependencies 1627 1628 if [ -n "${setupHook:-}" ]; then 1629 mkdir -p "${!outputDev}/nix-support" 1630 substituteAll "$setupHook" "${!outputDev}/nix-support/setup-hook" 1631 fi 1632 1633 # TODO(@Ericson2314): Remove after https://github.com/NixOS/nixpkgs/pull/31414 1634 if [ -n "${setupHooks:-}" ]; then 1635 mkdir -p "${!outputDev}/nix-support" 1636 local hook 1637 # have to use ${setupHooks[@]} without quotes because it needs to support setupHooks being a array or a whitespace separated string 1638 # # values of setupHooks won't have spaces so it won't cause problems 1639 # shellcheck disable=2068 1640 for hook in ${setupHooks[@]}; do 1641 local content 1642 consumeEntire content < "$hook" 1643 substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook" 1644 unset -v content 1645 done 1646 unset -v hook 1647 fi 1648 1649 # Propagate user-env packages into the output with binaries, TODO? 1650 1651 if [ -n "${propagatedUserEnvPkgs[*]:-}" ]; then 1652 mkdir -p "${!outputBin}/nix-support" 1653 printWords "${propagatedUserEnvPkgs[@]}" > "${!outputBin}/nix-support/propagated-user-env-packages" 1654 fi 1655 1656 runHook postFixup 1657} 1658 1659 1660installCheckPhase() { 1661 runHook preInstallCheck 1662 1663 if [[ -z "${foundMakefile:-}" ]]; then 1664 echo "no Makefile or custom installCheckPhase, doing nothing" 1665 #TODO(@oxij): should flagsArray influence make -n? 1666 elif [[ -z "${installCheckTarget:-}" ]] \ 1667 && ! make -n ${makefile:+-f $makefile} "${installCheckTarget:-installcheck}" >/dev/null 2>&1; then 1668 echo "no installcheck target in ${makefile:-Makefile}, doing nothing" 1669 else 1670 # Old bash empty array hack 1671 # shellcheck disable=SC2086 1672 local flagsArray=( 1673 ${enableParallelChecking:+-j${NIX_BUILD_CORES}} 1674 SHELL="$SHELL" 1675 ) 1676 1677 concatTo flagsArray makeFlags makeFlagsArray \ 1678 installCheckFlags installCheckFlagsArray installCheckTarget=installcheck 1679 1680 echoCmd 'installcheck flags' "${flagsArray[@]}" 1681 make ${makefile:+-f $makefile} "${flagsArray[@]}" 1682 unset flagsArray 1683 fi 1684 1685 runHook postInstallCheck 1686} 1687 1688 1689distPhase() { 1690 runHook preDist 1691 1692 local flagsArray=() 1693 concatTo flagsArray distFlags distFlagsArray distTarget=dist 1694 1695 echo 'dist flags: %q' "${flagsArray[@]}" 1696 make ${makefile:+-f $makefile} "${flagsArray[@]}" 1697 1698 if [ "${dontCopyDist:-0}" != 1 ]; then 1699 mkdir -p "$out/tarballs" 1700 1701 # Note: don't quote $tarballs, since we explicitly permit 1702 # wildcards in there. 1703 # shellcheck disable=SC2086 1704 cp -pvd ${tarballs[*]:-*.tar.gz} "$out/tarballs" 1705 fi 1706 1707 runHook postDist 1708} 1709 1710 1711showPhaseHeader() { 1712 local phase="$1" 1713 echo "Running phase: $phase" 1714 1715 # The Nix structured logger allows derivations to update the phase as they're building, 1716 # which shows up in the terminal UI. See `handleJSONLogMessage` in the Nix source. 1717 if [[ -z ${NIX_LOG_FD-} ]]; then 1718 return 1719 fi 1720 printf "@nix { \"action\": \"setPhase\", \"phase\": \"%s\" }\n" "$phase" >&"$NIX_LOG_FD" 1721} 1722 1723 1724showPhaseFooter() { 1725 local phase="$1" 1726 local startTime="$2" 1727 local endTime="$3" 1728 local delta=$(( endTime - startTime )) 1729 (( delta < 30 )) && return 1730 1731 local H=$((delta/3600)) 1732 local M=$((delta%3600/60)) 1733 local S=$((delta%60)) 1734 echo -n "$phase completed in " 1735 (( H > 0 )) && echo -n "$H hours " 1736 (( M > 0 )) && echo -n "$M minutes " 1737 echo "$S seconds" 1738} 1739 1740 1741runPhase() { 1742 local curPhase="$*" 1743 if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then return; fi 1744 if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then return; fi 1745 if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then return; fi 1746 if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then return; fi 1747 if [[ "$curPhase" = checkPhase && -z "${doCheck:-}" ]]; then return; fi 1748 if [[ "$curPhase" = installPhase && -n "${dontInstall:-}" ]]; then return; fi 1749 if [[ "$curPhase" = fixupPhase && -n "${dontFixup:-}" ]]; then return; fi 1750 if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then return; fi 1751 if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then return; fi 1752 1753 showPhaseHeader "$curPhase" 1754 dumpVars 1755 1756 local startTime endTime 1757 startTime=$(date +"%s") 1758 1759 # Evaluate the variable named $curPhase if it exists, otherwise the 1760 # function named $curPhase. 1761 eval "${!curPhase:-$curPhase}" 1762 1763 endTime=$(date +"%s") 1764 1765 showPhaseFooter "$curPhase" "$startTime" "$endTime" 1766 1767 if [ "$curPhase" = unpackPhase ]; then 1768 # make sure we can cd into the directory 1769 [ -n "${sourceRoot:-}" ] && chmod +x -- "${sourceRoot}" 1770 1771 cd -- "${sourceRoot:-.}" 1772 fi 1773} 1774 1775 1776genericBuild() { 1777 # variable used by our gzip wrapper to add -n. 1778 # 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. 1779 export GZIP_NO_TIMESTAMPS=1 1780 1781 if [ -f "${buildCommandPath:-}" ]; then 1782 source "$buildCommandPath" 1783 return 1784 fi 1785 if [ -n "${buildCommand:-}" ]; then 1786 eval "$buildCommand" 1787 return 1788 fi 1789 1790 if [ -z "${phases[*]:-}" ]; then 1791 phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} \ 1792 configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase \ 1793 ${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase \ 1794 ${preDistPhases[*]:-} distPhase ${postPhases[*]:-}"; 1795 fi 1796 1797 # The use of ${phases[*]} gives the correct behavior both with and 1798 # without structured attrs. This relies on the fact that each 1799 # phase name is space-free, which it must be because it's the name 1800 # of either a shell variable or a shell function. 1801 for curPhase in ${phases[*]}; do 1802 runPhase "$curPhase" 1803 done 1804} 1805 1806 1807# Execute the post-hooks. 1808runHook postHook 1809 1810 1811# Execute the global user hook (defined through the Nixpkgs 1812# configuration option ‘stdenv.userHook’). This can be used to set 1813# global compiler optimisation flags, for instance. 1814runHook userHook 1815 1816 1817dumpVars 1818 1819 1820# Restore the original options for nix-shell 1821[[ $__nixpkgs_setup_set_original == *e* ]] || set +e 1822[[ $__nixpkgs_setup_set_original == *u* ]] || set +u 1823unset -v __nixpkgs_setup_set_original