summary refs log tree commit diff
path: root/pkgs/build-support/bintools-wrapper
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-08-04 10:43:07 +0000
committerAlyssa Ross <hi@alyssa.is>2021-08-04 10:43:07 +0000
commit62614cbef7da005c1eda8c9400160f6bcd6546b8 (patch)
treec2630f69080637987b68acb1ee8676d2681fe304 /pkgs/build-support/bintools-wrapper
parentd9c82ed3044c72cecf01c6ea042489d30914577c (diff)
parente24069138dfec3ef94f211f1da005bb5395adc11 (diff)
downloadnixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.gz
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.bz2
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.lz
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.xz
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.zst
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.zip
Merge branch 'nixpkgs-update' into master
Diffstat (limited to 'pkgs/build-support/bintools-wrapper')
-rw-r--r--pkgs/build-support/bintools-wrapper/add-darwin-ldflags-before.sh81
-rw-r--r--pkgs/build-support/bintools-wrapper/add-flags.sh5
-rwxr-xr-xpkgs/build-support/bintools-wrapper/darwin-install_name_tool-wrapper.sh49
-rwxr-xr-xpkgs/build-support/bintools-wrapper/darwin-strip-wrapper.sh78
-rw-r--r--pkgs/build-support/bintools-wrapper/default.nix140
-rw-r--r--pkgs/build-support/bintools-wrapper/ld-wrapper.sh66
6 files changed, 372 insertions, 47 deletions
diff --git a/pkgs/build-support/bintools-wrapper/add-darwin-ldflags-before.sh b/pkgs/build-support/bintools-wrapper/add-darwin-ldflags-before.sh
new file mode 100644
index 00000000000..75d9484846a
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/add-darwin-ldflags-before.sh
@@ -0,0 +1,81 @@
+# Unconditionally adding in platform version flags will result in warnings that
+# will be treated as errors by some packages. Add any missing flags here.
+
+# There are two things to be configured: the "platform version" (oldest
+# supported version of macos, ios, etc), and the "sdk version".
+#
+# The modern way of configuring these is to use:
+#    -platform_version $platform $platform_version $sdk_version"
+#
+# The old way is still supported, and uses flags like:
+#    -${platform}_version_min $platform_version
+#    -sdk_version $sdk_version
+#
+# If both styles are specified ld will combine them. If multiple versions are
+# specified for the same platform, ld will emit an error.
+#
+# The following adds flags for whichever properties have not already been
+# provided.
+
+havePlatformVersionFlag=
+haveDarwinSDKVersion=
+haveDarwinPlatformVersion=
+
+# Roles will set by add-flags.sh, but add-flags.sh can be skipped when the
+# cc-wrapper has added the linker flags. Both the cc-wrapper and the binutils
+# wrapper mangle the same variable (MACOSX_DEPLOYMENT_TARGET), so if roles are
+# empty due to being run through the cc-wrapper then the mangle here is a no-op
+# and we still do the right thing.
+#
+# To be robust, make sure we always have the correct set of roles.
+accumulateRoles
+
+mangleVarSingle @darwinMinVersionVariable@ ${role_suffixes[@]+"${role_suffixes[@]}"}
+
+n=0
+nParams=${#params[@]}
+while (( n < nParams )); do
+    p=${params[n]}
+    case "$p" in
+        # the current platform
+        -@darwinPlatform@_version_min)
+            haveDarwinPlatformVersion=1
+            ;;
+
+        # legacy aliases
+        -macosx_version_min|-iphoneos_version_min|-iosmac_version_min|-uikitformac_version_min)
+            haveDarwinPlatformVersion=1
+            ;;
+
+        -sdk_version)
+            haveDarwinSDKVersion=1
+            ;;
+
+        -platform_version)
+            havePlatformVersionFlag=1
+
+            # If clang can't determine the sdk version it will pass 0.0.0. This
+            # has runtime effects so we override this to use the known sdk
+            # version.
+            if [ "${params[n+3]-}" = 0.0.0 ]; then
+                params[n+3]=@darwinSdkVersion@
+            fi
+            ;;
+    esac
+    n=$((n + 1))
+done
+
+# If the caller has set -platform_version, trust they're doing the right thing.
+# This will be the typical case for clang in nixpkgs.
+if [ ! "$havePlatformVersionFlag" ]; then
+    if [ ! "$haveDarwinSDKVersion" ] && [ ! "$haveDarwinPlatformVersion" ]; then
+        # Nothing provided. Use the modern "-platform_version" to set both.
+        extraBefore+=(-platform_version @darwinPlatform@ "${@darwinMinVersionVariable@_@suffixSalt@:-@darwinMinVersion@}" @darwinSdkVersion@)
+    elif [ ! "$haveDarwinSDKVersion" ]; then
+        # Add missing sdk version
+        extraBefore+=(-sdk_version @darwinSdkVersion@)
+    elif [ ! "$haveDarwinPlatformVersion" ]; then
+        # Add missing platform version
+        extraBefore+=(-@darwinPlatform@_version_min "${@darwinMinVersionVariable@_@suffixSalt@:-@darwinMinVersion@}")
+    fi
+fi
diff --git a/pkgs/build-support/bintools-wrapper/add-flags.sh b/pkgs/build-support/bintools-wrapper/add-flags.sh
index e99beb38158..3b94daba65d 100644
--- a/pkgs/build-support/bintools-wrapper/add-flags.sh
+++ b/pkgs/build-support/bintools-wrapper/add-flags.sh
@@ -3,6 +3,7 @@ var_templates_list=(
     NIX_IGNORE_LD_THROUGH_GCC
     NIX_LDFLAGS
     NIX_LDFLAGS_BEFORE
+    NIX_DYNAMIC_LINKER
     NIX_LDFLAGS_AFTER
     NIX_LDFLAGS_HARDEN
     NIX_HARDENING_ENABLE
@@ -25,6 +26,10 @@ if [ -e @out@/nix-support/libc-ldflags ]; then
     NIX_LDFLAGS_@suffixSalt@+=" $(< @out@/nix-support/libc-ldflags)"
 fi
 
+if [ -z "$NIX_DYNAMIC_LINKER_@suffixSalt@" ] && [ -e @out@/nix-support/ld-set-dynamic-linker ]; then
+    NIX_DYNAMIC_LINKER_@suffixSalt@="$(< @out@/nix-support/dynamic-linker)"
+fi
+
 if [ -e @out@/nix-support/libc-ldflags-before ]; then
     NIX_LDFLAGS_BEFORE_@suffixSalt@="$(< @out@/nix-support/libc-ldflags-before) $NIX_LDFLAGS_BEFORE_@suffixSalt@"
 fi
diff --git a/pkgs/build-support/bintools-wrapper/darwin-install_name_tool-wrapper.sh b/pkgs/build-support/bintools-wrapper/darwin-install_name_tool-wrapper.sh
new file mode 100755
index 00000000000..376a7abfe41
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/darwin-install_name_tool-wrapper.sh
@@ -0,0 +1,49 @@
+#! @shell@
+# shellcheck shell=bash
+
+set -eu -o pipefail +o posix
+shopt -s nullglob
+
+if (( "${NIX_DEBUG:-0}" >= 7 )); then
+    set -x
+fi
+
+source @signingUtils@
+
+extraAfter=()
+extraBefore=()
+params=("$@")
+
+input=
+
+pprev=
+prev=
+for p in \
+    ${extraBefore+"${extraBefore[@]}"} \
+    ${params+"${params[@]}"} \
+    ${extraAfter+"${extraAfter[@]}"}
+do
+    if [ "$pprev" != "-change" ] && [[ "$prev" != -* ]] && [[ "$p" != -* ]]; then
+        input="$p"
+    fi
+    pprev="$prev"
+    prev="$p"
+done
+
+# Optionally print debug info.
+if (( "${NIX_DEBUG:-0}" >= 1 )); then
+    # Old bash workaround, see above.
+    echo "extra flags before to @prog@:" >&2
+    printf "  %q\n" ${extraBefore+"${extraBefore[@]}"}  >&2
+    echo "original flags to @prog@:" >&2
+    printf "  %q\n" ${params+"${params[@]}"} >&2
+    echo "extra flags after to @prog@:" >&2
+    printf "  %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
+fi
+
+@prog@ \
+    ${extraBefore+"${extraBefore[@]}"} \
+    ${params+"${params[@]}"} \
+    ${extraAfter+"${extraAfter[@]}"}
+
+sign "$input"
diff --git a/pkgs/build-support/bintools-wrapper/darwin-strip-wrapper.sh b/pkgs/build-support/bintools-wrapper/darwin-strip-wrapper.sh
new file mode 100755
index 00000000000..a67699547a6
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/darwin-strip-wrapper.sh
@@ -0,0 +1,78 @@
+#! @shell@
+# shellcheck shell=bash
+
+set -eu -o pipefail +o posix
+shopt -s nullglob
+
+if (( "${NIX_DEBUG:-0}" >= 7 )); then
+    set -x
+fi
+
+source @signingUtils@
+
+extraAfter=()
+extraBefore=()
+params=("$@")
+
+output=
+inputs=()
+
+restAreFiles=
+prev=
+for p in \
+    ${extraBefore+"${extraBefore[@]}"} \
+    ${params+"${params[@]}"} \
+    ${extraAfter+"${extraAfter[@]}"}
+do
+    if [ "$restAreFiles" ]; then
+        inputs+=("$p")
+    else
+        case "$prev" in
+            -s|-R|-d|-arch)
+                # Unrelated arguments with values
+                ;;
+            -o)
+                # Explicit output
+                output="$p"
+                ;;
+            *)
+                # Any other orgument either takes no value, or is a file.
+                if [[ "$p" != -* ]]; then
+                    inputs+=("$p")
+                fi
+                ;;
+        esac
+
+        if [ "$p" == - ]; then
+            restAreFiles=1
+        fi
+    fi
+
+    prev="$p"
+done
+
+# Optionally print debug info.
+if (( "${NIX_DEBUG:-0}" >= 1 )); then
+    # Old bash workaround, see above.
+    echo "extra flags before to @prog@:" >&2
+    printf "  %q\n" ${extraBefore+"${extraBefore[@]}"}  >&2
+    echo "original flags to @prog@:" >&2
+    printf "  %q\n" ${params+"${params[@]}"} >&2
+    echo "extra flags after to @prog@:" >&2
+    printf "  %q\n" ${extraAfter+"${extraAfter[@]}"} >&2
+fi
+
+@prog@ \
+    ${extraBefore+"${extraBefore[@]}"} \
+    ${params+"${params[@]}"} \
+    ${extraAfter+"${extraAfter[@]}"}
+
+if [ "$output" ]; then
+    # Single explicit output
+    signIfRequired "$output"
+else
+    # Multiple inputs, rewritten in place
+    for input in "${inputs[@]}"; do
+      signIfRequired "$input"
+    done
+fi
diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix
index 786f0f9c598..82d17369743 100644
--- a/pkgs/build-support/bintools-wrapper/default.nix
+++ b/pkgs/build-support/bintools-wrapper/default.nix
@@ -6,16 +6,34 @@
 # compiler and the linker just "work".
 
 { name ? ""
+, lib
 , stdenvNoCC
 , bintools ? null, libc ? null, coreutils ? null, shell ? stdenvNoCC.shell, gnugrep ? null
+, netbsd ? null, netbsdCross ? null
+, sharedLibraryLoader ?
+  if libc == null then
+    null
+  else if stdenvNoCC.targetPlatform.isNetBSD then
+    if !(targetPackages ? netbsdCross) then
+      netbsd.ld_elf_so
+    else if libc != targetPackages.netbsdCross.headers then
+      targetPackages.netbsdCross.ld_elf_so
+    else
+      null
+  else
+    lib.getLib libc
 , nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
 , propagateDoc ? bintools != null && bintools ? man
 , extraPackages ? [], extraBuildCommands ? ""
 , buildPackages ? {}
+, targetPackages ? {}
 , useMacosReexportHack ? false
+
+# Darwin code signing support utilities
+, postLinkSignHook ? null, signingUtils ? null
 }:
 
-with stdenvNoCC.lib;
+with lib;
 
 assert nativeTools -> !propagateDoc && nativePrefix != "";
 assert !nativeTools ->
@@ -31,11 +49,11 @@ let
   #
   # TODO(@Ericson2314) Make unconditional, or optional but always true by
   # default.
-  targetPrefix = stdenv.lib.optionalString (targetPlatform != hostPlatform)
+  targetPrefix = lib.optionalString (targetPlatform != hostPlatform)
                                         (targetPlatform.config + "-");
 
-  bintoolsVersion = stdenv.lib.getVersion bintools;
-  bintoolsName = stdenv.lib.removePrefix targetPrefix (stdenv.lib.getName bintools);
+  bintoolsVersion = lib.getVersion bintools;
+  bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools);
 
   libc_bin = if libc == null then null else getBin libc;
   libc_dev = if libc == null then null else getDev libc;
@@ -50,19 +68,22 @@ let
   # The dynamic linker has different names on different platforms. This is a
   # shell glob that ought to match it.
   dynamicLinker =
-    /**/ if libc == null then null
-    else if targetPlatform.libc == "musl"             then "${libc_lib}/lib/ld-musl-*"
-    else if targetPlatform.libc == "bionic"           then "/system/bin/linker"
-    else if targetPlatform.libc == "nblibc"           then "${libc_lib}/libexec/ld.elf_so"
-    else if targetPlatform.system == "i686-linux"     then "${libc_lib}/lib/ld-linux.so.2"
-    else if targetPlatform.system == "x86_64-linux"   then "${libc_lib}/lib/ld-linux-x86-64.so.2"
+    /**/ if sharedLibraryLoader == null then null
+    else if targetPlatform.libc == "musl"             then "${sharedLibraryLoader}/lib/ld-musl-*"
+    else if (targetPlatform.libc == "bionic" && targetPlatform.is32bit) then "/system/bin/linker"
+    else if (targetPlatform.libc == "bionic" && targetPlatform.is64bit) then "/system/bin/linker64"
+    else if targetPlatform.libc == "nblibc"           then "${sharedLibraryLoader}/libexec/ld.elf_so"
+    else if targetPlatform.system == "i686-linux"     then "${sharedLibraryLoader}/lib/ld-linux.so.2"
+    else if targetPlatform.system == "x86_64-linux"   then "${sharedLibraryLoader}/lib/ld-linux-x86-64.so.2"
+    else if targetPlatform.system == "powerpc64le-linux" then "${sharedLibraryLoader}/lib/ld64.so.2"
     # ARM with a wildcard, which can be "" or "-armhf".
-    else if (with targetPlatform; isAarch32 && isLinux)   then "${libc_lib}/lib/ld-linux*.so.3"
-    else if targetPlatform.system == "aarch64-linux"  then "${libc_lib}/lib/ld-linux-aarch64.so.1"
-    else if targetPlatform.system == "powerpc-linux"  then "${libc_lib}/lib/ld.so.1"
-    else if targetPlatform.isMips                     then "${libc_lib}/lib/ld.so.1"
+    else if (with targetPlatform; isAarch32 && isLinux)   then "${sharedLibraryLoader}/lib/ld-linux*.so.3"
+    else if targetPlatform.system == "aarch64-linux"  then "${sharedLibraryLoader}/lib/ld-linux-aarch64.so.1"
+    else if targetPlatform.system == "powerpc-linux"  then "${sharedLibraryLoader}/lib/ld.so.1"
+    else if targetPlatform.isMips                     then "${sharedLibraryLoader}/lib/ld.so.1"
     else if targetPlatform.isDarwin                   then "/usr/lib/dyld"
-    else if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
+    else if targetPlatform.isFreeBSD                  then "/libexec/ld-elf.so.1"
+    else if lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
     else null;
 
   expand-response-params =
@@ -167,7 +188,7 @@ stdenv.mkDerivation {
       else if targetPlatform.isWindows then "pe"
       else "elf" + toString targetPlatform.parsed.cpu.bits;
     endianPrefix = if targetPlatform.isBigEndian then "big" else "little";
-    sep = optionalString (!targetPlatform.isMips && !targetPlatform.isPower) "-";
+    sep = optionalString (!targetPlatform.isMips && !targetPlatform.isPower && !targetPlatform.isRiscV) "-";
     arch =
       /**/ if targetPlatform.isAarch64 then endianPrefix + "aarch64"
       else if targetPlatform.isAarch32     then endianPrefix + "arm"
@@ -179,15 +200,20 @@ stdenv.mkDerivation {
           mips64   = "btsmip";
           mips64el = "ltsmip";
         }.${targetPlatform.parsed.cpu.name}
+      else if targetPlatform.isMmix then "mmix"
       else if targetPlatform.isPower then if targetPlatform.isBigEndian then "ppc" else "lppc"
       else if targetPlatform.isSparc then "sparc"
       else if targetPlatform.isMsp430 then "msp430"
       else if targetPlatform.isAvr then "avr"
       else if targetPlatform.isAlpha then "alpha"
       else if targetPlatform.isVc4 then "vc4"
+      else if targetPlatform.isOr1k then "or1k"
+      else if targetPlatform.isM68k then "m68k"
+      else if targetPlatform.isS390 then "s390"
+      else if targetPlatform.isRiscV then "lriscv"
       else throw "unknown emulation for platform: ${targetPlatform.config}";
     in if targetPlatform.useLLVM or false then ""
-       else targetPlatform.platform.bfdEmulation or (fmt + sep + arch);
+       else targetPlatform.bfdEmulation or (fmt + sep + arch);
 
   strictDeps = true;
   depsTargetTargetPropagated = extraPackages;
@@ -214,10 +240,10 @@ stdenv.mkDerivation {
     ##
     ## Dynamic linker support
     ##
-    + ''
+    + optionalString (sharedLibraryLoader != null) ''
       if [[ -z ''${dynamicLinker+x} ]]; then
         echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2
-        local dynamicLinker="${libc_lib}/lib/ld*.so.?"
+        local dynamicLinker="${sharedLibraryLoader}/lib/ld*.so.?"
       fi
     ''
 
@@ -234,27 +260,17 @@ stdenv.mkDerivation {
       if [ -n "''${dynamicLinker-}" ]; then
         echo $dynamicLinker > $out/nix-support/dynamic-linker
 
-    '' + (if targetPlatform.isDarwin then ''
-        printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
-      '' else ''
-        if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then
-          echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
-        fi
-      ''
-      # The dynamic linker is passed in `ldflagsBefore' to allow
-      # explicit overrides of the dynamic linker by callers to ld
-      # (the *last* value counts, so ours should come first).
-      + ''
-        echo -dynamic-linker "$dynamicLinker" >> $out/nix-support/libc-ldflags-before
-    '') + ''
+        ${if targetPlatform.isDarwin then ''
+          printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
+        '' else lib.optionalString (sharedLibraryLoader != null) ''
+          if [ -e ${sharedLibraryLoader}/lib/32/ld-linux.so.2 ]; then
+            echo ${sharedLibraryLoader}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
+          fi
+          touch $out/nix-support/ld-set-dynamic-linker
+        ''}
       fi
     '')
 
-    # Ensure consistent LC_VERSION_MIN_MACOSX and remove LC_UUID.
-    + optionalString stdenv.targetPlatform.isMacOS ''
-      echo "-macosx_version_min 10.12 -sdk_version 10.12 -no_uuid" >> $out/nix-support/libc-ldflags-before
-    ''
-
     ##
     ## User env support
     ##
@@ -304,6 +320,17 @@ stdenv.mkDerivation {
       done
     ''
 
+    + optionalString stdenv.targetPlatform.isDarwin ''
+      echo "-arch ${targetPlatform.darwinArch}" >> $out/nix-support/libc-ldflags
+    ''
+
+    ###
+    ### Remove LC_UUID
+    ###
+    + optionalString (stdenv.targetPlatform.isDarwin && !(stdenv.cc.bintools.bintools.isGNU or false)) ''
+      echo "-no_uuid" >> $out/nix-support/libc-ldflags-before
+    ''
+
     + ''
       for flags in "$out/nix-support"/*flags*; do
         substituteInPlace "$flags" --replace $'\n' ' '
@@ -314,6 +341,41 @@ stdenv.mkDerivation {
       substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash
     ''
 
+    ###
+    ### Ensure consistent LC_VERSION_MIN_MACOSX
+    ###
+    + optionalString stdenv.targetPlatform.isDarwin (
+      let
+        inherit (stdenv.targetPlatform)
+          darwinPlatform darwinSdkVersion
+          darwinMinVersion darwinMinVersionVariable;
+      in ''
+        export darwinPlatform=${darwinPlatform}
+        export darwinMinVersion=${darwinMinVersion}
+        export darwinSdkVersion=${darwinSdkVersion}
+        export darwinMinVersionVariable=${darwinMinVersionVariable}
+        substituteAll ${./add-darwin-ldflags-before.sh} $out/nix-support/add-local-ldflags-before.sh
+      ''
+    )
+
+    ##
+    ## Code signing on Apple Silicon
+    ##
+    + optionalString (targetPlatform.isDarwin && targetPlatform.isAarch64) ''
+      echo 'source ${postLinkSignHook}' >> $out/nix-support/post-link-hook
+
+      export signingUtils=${signingUtils}
+
+      wrap \
+        ${targetPrefix}install_name_tool \
+        ${./darwin-install_name_tool-wrapper.sh} \
+        "${bintools_bin}/bin/${targetPrefix}install_name_tool"
+
+      wrap \
+        ${targetPrefix}strip ${./darwin-strip-wrapper.sh} \
+        "${bintools_bin}/bin/${targetPrefix}strip"
+    ''
+
     ##
     ## Extra custom steps
     ##
@@ -328,10 +390,10 @@ stdenv.mkDerivation {
     let bintools_ = if bintools != null then bintools else {}; in
     (if bintools_ ? meta then removeAttrs bintools.meta ["priority"] else {}) //
     { description =
-        stdenv.lib.attrByPath ["meta" "description"] "System binary utilities" bintools_
+        lib.attrByPath ["meta" "description"] "System binary utilities" bintools_
         + " (wrapper script)";
       priority = 10;
   } // optionalAttrs useMacosReexportHack {
-    platforms = stdenv.lib.platforms.darwin;
+    platforms = lib.platforms.darwin;
   };
 }
diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
index 81b5a90edd5..2f96480f80c 100644
--- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
+++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
@@ -23,11 +23,22 @@ fi
 
 # Optionally filter out paths not refering to the store.
 expandResponseParams "$@"
+
+# NIX_LINK_TYPE is set if ld has been called through our cc wrapper. We take
+# advantage of this to avoid both recalculating it, and also repeating other
+# processing cc wrapper has already done.
+if [[ -n "${NIX_LINK_TYPE_@suffixSalt@:-}" ]]; then
+    linkType=$NIX_LINK_TYPE_@suffixSalt@
+else
+    linkType=$(checkLinkType "$@")
+fi
+
 if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}"
-        && ( -z "$NIX_IGNORE_LD_THROUGH_GCC_@suffixSalt@" || -z "${NIX_LDFLAGS_SET_@suffixSalt@:-}" ) ]]; then
+        && ( -z "$NIX_IGNORE_LD_THROUGH_GCC_@suffixSalt@" || -z "${NIX_LINK_TYPE_@suffixSalt@:-}" ) ]]; then
     rest=()
     nParams=${#params[@]}
     declare -i n=0
+
     while (( "$n" < "$nParams" )); do
         p=${params[n]}
         p2=${params[n+1]:-} # handle `p` being last one
@@ -55,17 +66,32 @@ if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}"
     params=(${rest+"${rest[@]}"})
 fi
 
+
 source @out@/nix-support/add-hardening.sh
 
 extraAfter=()
 extraBefore=(${hardeningLDFlags[@]+"${hardeningLDFlags[@]}"})
 
-if [ -z "${NIX_LDFLAGS_SET_@suffixSalt@:-}" ]; then
-    extraAfter+=($NIX_LDFLAGS_@suffixSalt@)
-    extraBefore+=($NIX_LDFLAGS_BEFORE_@suffixSalt@)
+if [ -z "${NIX_LINK_TYPE_@suffixSalt@:-}" ]; then
+    extraAfter+=($(filterRpathFlags "$linkType" $NIX_LDFLAGS_@suffixSalt@))
+    extraBefore+=($(filterRpathFlags "$linkType" $NIX_LDFLAGS_BEFORE_@suffixSalt@))
+
+    # By adding dynamic linker to extraBefore we allow the users set their
+    # own dynamic linker as NIX_LD_FLAGS will override earlier set flags
+    if [[ "$linkType" == dynamic && -n "$NIX_DYNAMIC_LINKER_@suffixSalt@" ]]; then
+        extraBefore+=("-dynamic-linker" "$NIX_DYNAMIC_LINKER_@suffixSalt@")
+    fi
+fi
+
+extraAfter+=($(filterRpathFlags "$linkType" $NIX_LDFLAGS_AFTER_@suffixSalt@))
+
+# These flags *must not* be pulled up to -Wl, flags, so they can't go in
+# add-flags.sh. They must always be set, so must not be disabled by
+# NIX_LDFLAGS_SET.
+if [ -e @out@/nix-support/add-local-ldflags-before.sh ]; then
+    source @out@/nix-support/add-local-ldflags-before.sh
 fi
 
-extraAfter+=($NIX_LDFLAGS_AFTER_@suffixSalt@)
 
 # Specify the target emulation if nothing is passed in ("-m" overrides this
 # environment variable). Ensures we never blindly fallback on targeting the host
@@ -83,6 +109,8 @@ declare -a libDirs
 declare -A libs
 declare -i relocatable=0 link32=0
 
+linkerOutput="a.out"
+
 if
     [ "$NIX_DONT_SET_RPATH_@suffixSalt@" != 1 ] \
         || [ "$NIX_SET_BUILD_ID_@suffixSalt@" = 1 ] \
@@ -134,7 +162,25 @@ then
     done
 fi
 
-if [ -e "@out@/nix-support/dynamic-linker-m32" ] && (( "$link32" )); then
+# Determine linkerOutput
+prev=
+for p in \
+    ${extraBefore+"${extraBefore[@]}"} \
+    ${params+"${params[@]}"} \
+    ${extraAfter+"${extraAfter[@]}"}
+do
+    case "$prev" in
+        -o)
+            # Informational for post-link-hook
+            linkerOutput="$p"
+            ;;
+        *)
+            ;;
+    esac
+    prev="$p"
+done
+
+if [[ "$link32" == "1" && "$linkType" == dynamic && -e "@out@/nix-support/dynamic-linker-m32" ]]; then
     # We have an alternate 32-bit linker and we're producing a 32-bit ELF, let's
     # use it.
     extraAfter+=(
@@ -144,7 +190,7 @@ if [ -e "@out@/nix-support/dynamic-linker-m32" ] && (( "$link32" )); then
 fi
 
 # Add all used dynamic libraries to the rpath.
-if [ "$NIX_DONT_SET_RPATH_@suffixSalt@" != 1 ]; then
+if [[ "$NIX_DONT_SET_RPATH_@suffixSalt@" != 1 && "$linkType" != static-pie ]]; then
     # For each directory in the library search path (-L...),
     # see if it contains a dynamic library used by a -l... flag.  If
     # so, add the directory to the rpath.
@@ -204,7 +250,11 @@ fi
 
 PATH="$path_backup"
 # Old bash workaround, see above.
-exec @prog@ \
+@prog@ \
     ${extraBefore+"${extraBefore[@]}"} \
     ${params+"${params[@]}"} \
     ${extraAfter+"${extraAfter[@]}"}
+
+if [ -e "@out@/nix-support/post-link-hook" ]; then
+    source @out@/nix-support/post-link-hook
+fi