diff options
Diffstat (limited to 'nixpkgs/pkgs/build-support/bintools-wrapper')
7 files changed, 988 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/add-flags.sh b/nixpkgs/pkgs/build-support/bintools-wrapper/add-flags.sh new file mode 100644 index 000000000000..e5c0556556c7 --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/add-flags.sh @@ -0,0 +1,32 @@ +# See cc-wrapper for comments. +var_templates_list=( + NIX+IGNORE_LD_THROUGH_GCC + NIX+LDFLAGS + NIX+LDFLAGS_BEFORE + NIX+LDFLAGS_AFTER + NIX+LDFLAGS_HARDEN + NIX+HARDENING_ENABLE +) +var_templates_bool=( + NIX+SET_BUILD_ID + NIX+DONT_SET_RPATH +) + +accumulateRoles + +for var in "${var_templates_list[@]}"; do + mangleVarList "$var" ${role_infixes[@]+"${role_infixes[@]}"} +done +for var in "${var_templates_bool[@]}"; do + mangleVarBool "$var" ${role_infixes[@]+"${role_infixes[@]}"} +done + +if [ -e @out@/nix-support/libc-ldflags ]; then + NIX_@infixSalt@_LDFLAGS+=" $(< @out@/nix-support/libc-ldflags)" +fi + +if [ -e @out@/nix-support/libc-ldflags-before ]; then + NIX_@infixSalt@_LDFLAGS_BEFORE="$(< @out@/nix-support/libc-ldflags-before) $NIX_@infixSalt@_LDFLAGS_BEFORE" +fi + +export NIX_BINTOOLS_WRAPPER_@infixSalt@_FLAGS_SET=1 diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/add-hardening.sh b/nixpkgs/pkgs/build-support/bintools-wrapper/add-hardening.sh new file mode 100644 index 000000000000..b7180870860a --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/add-hardening.sh @@ -0,0 +1,58 @@ +declare -a hardeningLDFlags=() + +declare -A hardeningEnableMap=() + +# Intentionally word-split in case 'NIX_HARDENING_ENABLE' is defined in Nix. The +# array expansion also prevents undefined variables from causing trouble with +# `set -u`. +for flag in ${NIX_@infixSalt@_HARDENING_ENABLE-}; do + hardeningEnableMap["$flag"]=1 +done + +# Remove unsupported flags. +for flag in @hardening_unsupported_flags@; do + unset -v "hardeningEnableMap[$flag]" +done + +if (( "${NIX_DEBUG:-0}" >= 1 )); then + declare -a allHardeningFlags=(pie relro bindnow) + declare -A hardeningDisableMap=() + + # Determine which flags were effectively disabled so we can report below. + for flag in "${allHardeningFlags[@]}"; do + if [[ -z "${hardeningEnableMap[$flag]-}" ]]; then + hardeningDisableMap[$flag]=1 + fi + done + + printf 'HARDENING: disabled flags:' >&2 + (( "${#hardeningDisableMap[@]}" )) && printf ' %q' "${!hardeningDisableMap[@]}" >&2 + echo >&2 + + if (( "${#hardeningEnableMap[@]}" )); then + echo 'HARDENING: Is active (not completely disabled with "all" flag)' >&2; + fi +fi + +for flag in "${!hardeningEnableMap[@]}"; do + case $flag in + pie) + if [[ ! ("$*" =~ " -shared " || "$*" =~ " -static ") ]]; then + if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling LDFlags -pie >&2; fi + hardeningLDFlags+=('-pie') + fi + ;; + relro) + if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling relro >&2; fi + hardeningLDFlags+=('-z' 'relro') + ;; + bindnow) + if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling bindnow >&2; fi + hardeningLDFlags+=('-z' 'now') + ;; + *) + # Ignore unsupported. Checked in Nix that at least *some* + # tool supports each flag. + ;; + esac +done diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix b/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix new file mode 100644 index 000000000000..e1ec09bc95a1 --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix @@ -0,0 +1,337 @@ +# The Nixpkgs CC is not directly usable, since it doesn't know where +# the C library and standard header files are. Therefore the compiler +# produced by that package cannot be installed directly in a user +# environment and used from the command line. So we use a wrapper +# script that sets up the right environment variables so that the +# compiler and the linker just "work". + +{ name ? "" +, stdenvNoCC +, bintools ? null, libc ? null, coreutils ? null, shell ? stdenvNoCC.shell, gnugrep ? null +, nativeTools, noLibc ? false, nativeLibc, nativePrefix ? "" +, propagateDoc ? bintools != null && bintools ? man +, extraPackages ? [], extraBuildCommands ? "" +, buildPackages ? {} +, useMacosReexportHack ? false +}: + +with stdenvNoCC.lib; + +assert nativeTools -> !propagateDoc && nativePrefix != ""; +assert !nativeTools -> + bintools != null && coreutils != null && gnugrep != null; +assert !(nativeLibc && noLibc); +assert (noLibc || nativeLibc) == (libc == null); + +let + stdenv = stdenvNoCC; + inherit (stdenv) hostPlatform targetPlatform; + + # Prefix for binaries. Customarily ends with a dash separator. + # + # TODO(@Ericson2314) Make unconditional, or optional but always true by + # default. + targetPrefix = stdenv.lib.optionalString (targetPlatform != hostPlatform) + (targetPlatform.config + "-"); + + bintoolsVersion = (builtins.parseDrvName bintools.name).version; + bintoolsName = (builtins.parseDrvName bintools.name).name; + + libc_bin = if libc == null then null else getBin libc; + libc_dev = if libc == null then null else getDev libc; + libc_lib = if libc == null then null else getLib libc; + bintools_bin = if nativeTools then "" else getBin bintools; + # The wrapper scripts use 'cat' and 'grep', so we may need coreutils. + coreutils_bin = if nativeTools then "" else getBin coreutils; + + # See description in cc-wrapper. + infixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config; + + # 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" + # 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 targetPlatform.isDarwin then "/usr/lib/dyld" + else if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" + else null; + + expand-response-params = + if buildPackages.stdenv.cc or null != null && buildPackages.stdenv.cc != "/dev/null" + then import ../expand-response-params { inherit (buildPackages) stdenv; } + else ""; + +in + +stdenv.mkDerivation { + name = targetPrefix + + (if name != "" then name else stdenv.lib.removePrefix targetPrefix "${bintoolsName}-wrapper") + + (stdenv.lib.optionalString (bintools != null && bintoolsVersion != "") "-${bintoolsVersion}"); + + preferLocalBuild = true; + + inherit bintools_bin libc_bin libc_dev libc_lib coreutils_bin; + shell = getBin shell + shell.shellPath or ""; + gnugrep_bin = if nativeTools then "" else gnugrep; + + inherit targetPrefix infixSalt; + + outputs = [ "out" ] ++ optionals propagateDoc [ "man" "info" ]; + + passthru = { + inherit bintools libc nativeTools nativeLibc nativePrefix; + + emacsBufferSetup = pkgs: '' + ; We should handle propagation here too + (mapc + (lambda (arg) + (when (file-directory-p (concat arg "/lib")) + (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib"))) + (when (file-directory-p (concat arg "/lib64")) + (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib64")))) + '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)})) + ''; + }; + + dontBuild = true; + dontConfigure = true; + + unpackPhase = '' + src=$PWD + ''; + + installPhase = + '' + set -u + + mkdir -p $out/bin $out/nix-support + + wrap() { + local dst="$1" + local wrapper="$2" + export prog="$3" + set +u + substituteAll "$wrapper" "$out/bin/$dst" + set -u + chmod +x "$out/bin/$dst" + } + '' + + + (if nativeTools then '' + echo ${nativePrefix} > $out/nix-support/orig-bintools + + ldPath="${nativePrefix}/bin" + '' else '' + echo $bintools_bin > $out/nix-support/orig-bintools + + ldPath="${bintools_bin}/bin" + '' + + + optionalString (targetPlatform.isSunOS && nativePrefix != "") '' + # Solaris needs an additional ld wrapper. + ldPath="${nativePrefix}/bin" + exec="$ldPath/${targetPrefix}ld" + wrap ld-solaris ${./ld-solaris-wrapper.sh} + '') + + + '' + # Create a symlink to as (the assembler). + if [ -e $ldPath/${targetPrefix}as ]; then + ln -s $ldPath/${targetPrefix}as $out/bin/${targetPrefix}as + fi + + '' + (if !useMacosReexportHack then '' + wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld} + '' else '' + ldInner="${targetPrefix}ld-reexport-delegate" + wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${targetPrefix}ld} + wrap "${targetPrefix}ld" ${./ld-wrapper.sh} "$out/bin/$ldInner" + unset ldInner + '') + '' + + for variant in ld.gold ld.bfd ld.lld; do + local underlying=$ldPath/${targetPrefix}$variant + [[ -e "$underlying" ]] || continue + wrap ${targetPrefix}$variant ${./ld-wrapper.sh} $underlying + done + + set +u + ''; + + emulation = let + fmt = + /**/ if targetPlatform.isDarwin then "mach-o" + 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) "-"; + arch = + /**/ if targetPlatform.isAarch64 then endianPrefix + "aarch64" + else if targetPlatform.isAarch32 then endianPrefix + "arm" + else if targetPlatform.isx86_64 then "x86-64" + else if targetPlatform.isx86_32 then "i386" + else if targetPlatform.isMips then { + "mips" = "btsmipn32"; # n32 variant + "mipsel" = "ltsmipn32"; # n32 variant + "mips64" = "btsmip"; + "mips64el" = "ltsmip"; + }.${targetPlatform.parsed.cpu.name} + 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 throw "unknown emulation for platform: ${targetPlatform.config}"; + in if targetPlatform.useLLVM or false then "" + else targetPlatform.platform.bfdEmulation or (fmt + sep + arch); + + strictDeps = true; + depsTargetTargetPropagated = extraPackages; + + wrapperName = "BINTOOLS_WRAPPER"; + + setupHooks = [ + ../setup-hooks/role.bash + ./setup-hook.sh + ]; + + postFixup = + '' + set -u + '' + + + optionalString (libc != null) ('' + ## + ## General libc support + ## + + echo "-L${libc_lib}${libc.libdir or "/lib"}" > $out/nix-support/libc-ldflags + + echo "${libc_lib}" > $out/nix-support/orig-libc + echo "${libc_dev}" > $out/nix-support/orig-libc-dev + + ## + ## Dynamic linker support + ## + + 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.?" + fi + + # Expand globs to fill array of options + dynamicLinker=($dynamicLinker) + + case ''${#dynamicLinker[@]} in + 0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;; + 1) echo "Using dynamic linker: '$dynamicLinker'" >&2;; + *) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;; + esac + + 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 + + local ldflagsBefore=(-dynamic-linker "$dynamicLinker") + '') + '' + 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). + printWords "''${ldflagsBefore[@]}" > $out/nix-support/libc-ldflags-before + '') + + + optionalString (!nativeTools) '' + ## + ## User env support + ## + + # Propagate the underling unwrapped bintools so that if you + # install the wrapper, you get tools like objdump (same for any + # binaries of libc). + printWords ${bintools_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages + '' + + + optionalString propagateDoc '' + ## + ## Man page and info support + ## + + ln -s ${bintools.man} $man + ln -s ${bintools.info} $info + '' + + + '' + ## + ## Hardening support + ## + + # some linkers on some platforms don't support specific -z flags + export hardening_unsupported_flags="" + if [[ "$($ldPath/${targetPrefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then + hardening_unsupported_flags+=" bindnow" + fi + if [[ "$($ldPath/${targetPrefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then + hardening_unsupported_flags+=" relro" + fi + '' + + + optionalString hostPlatform.isCygwin '' + hardening_unsupported_flags+=" pic" + '' + + + optionalString targetPlatform.isAvr '' + hardening_unsupported_flags+=" relro bindnow" + '' + + + optionalString (libc != null && targetPlatform.isAvr) '' + for isa in avr5 avr3 avr4 avr6 avr25 avr31 avr35 avr51 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack; do + echo "-L${getLib libc}/avr/lib/$isa" >> $out/nix-support/libc-cflags + done + '' + + + '' + set +u + substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh + substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh + substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash + + ## + ## Extra custom steps + ## + '' + + + extraBuildCommands; + + inherit dynamicLinker expand-response-params; + + # for substitution in utils.bash + expandResponseParams = "${expand-response-params}/bin/expand-response-params"; + + meta = + 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_ + + " (wrapper script)"; + priority = 10; + } // optionalAttrs useMacosReexportHack { + platforms = stdenv.lib.platforms.darwin; + }; +} diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh b/nixpkgs/pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh new file mode 100644 index 000000000000..5d81e34a047f --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh @@ -0,0 +1,29 @@ +#!@shell@ +set -eu -o pipefail +shopt -s nullglob + +if (( "${NIX_DEBUG:-0}" >= 7 )); then + set -x +fi + +declare -a args=("$@") +# I've also tried adding -z direct and -z lazyload, but it gave too many problems with C++ exceptions :'( +# Also made sure libgcc would not be lazy-loaded, as suggested here: https://www.illumos.org/issues/2534#note-3 +# but still no success. +declare -a argsBefore=(-z ignore) argsAfter=() + +# This loop makes sure all -L arguments are before -l arguments, or ld may complain it cannot find a library. +# GNU binutils does not have this problem: +# http://stackoverflow.com/questions/5817269/does-the-order-of-l-and-l-options-in-the-gnu-linker-matter +while (( $# )); do + case "${args[$i]}" in + -L) argsBefore+=("$1" "$2"); shift ;; + -L?*) argsBefore+=("$1") ;; + *) argsAfter+=("$1") ;; + esac + shift +done + +# Trace: +set -x +exec "@ld@" "${argsBefore[@]}" "${argsAfter[@]}" diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/nixpkgs/pkgs/build-support/bintools-wrapper/ld-wrapper.sh new file mode 100644 index 000000000000..ed2f00a8974e --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/ld-wrapper.sh @@ -0,0 +1,210 @@ +#! @shell@ +set -eu -o pipefail +o posix +shopt -s nullglob + +if (( "${NIX_DEBUG:-0}" >= 7 )); then + set -x +fi + +path_backup="$PATH" + +# phase separation makes this look useless +# shellcheck disable=SC2157 +if [ -n "@coreutils_bin@" ]; then + PATH="@coreutils_bin@/bin" +fi + +source @out@/nix-support/utils.bash + +if [ -z "${NIX_BINTOOLS_WRAPPER_@infixSalt@_FLAGS_SET:-}" ]; then + source @out@/nix-support/add-flags.sh +fi + + +# Optionally filter out paths not refering to the store. +expandResponseParams "$@" +if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}" + && ( -z "$NIX_@infixSalt@_IGNORE_LD_THROUGH_GCC" || -z "${NIX_@infixSalt@_LDFLAGS_SET:-}" ) ]]; then + rest=() + nParams=${#params[@]} + declare -i n=0 + while (( "$n" < "$nParams" )); do + p=${params[n]} + p2=${params[n+1]:-} # handle `p` being last one + if [ "${p:0:3}" = -L/ ] && badPath "${p:2}"; then + skip "${p:2}" + elif [ "$p" = -L ] && badPath "$p2"; then + n+=1; skip "$p2" + elif [ "$p" = -rpath ] && badPath "$p2"; then + n+=1; skip "$p2" + elif [ "$p" = -dynamic-linker ] && badPath "$p2"; then + n+=1; skip "$p2" + elif [ "${p:0:1}" = / ] && badPath "$p"; then + # We cannot skip this; barf. + echo "impure path \`$p' used in link" >&2 + exit 1 + elif [ "${p:0:9}" = --sysroot ]; then + # Our ld is not built with sysroot support (Can we fix that?) + : + else + rest+=("$p") + fi + n+=1 + done + # Old bash empty array hack + params=(${rest+"${rest[@]}"}) +fi + +source @out@/nix-support/add-hardening.sh + +extraAfter=() +extraBefore=(${hardeningLDFlags[@]+"${hardeningLDFlags[@]}"}) + +if [ -z "${NIX_@infixSalt@_LDFLAGS_SET:-}" ]; then + extraAfter+=($NIX_@infixSalt@_LDFLAGS) + extraBefore+=($NIX_@infixSalt@_LDFLAGS_BEFORE) +fi + +extraAfter+=($NIX_@infixSalt@_LDFLAGS_AFTER) + +# Specify the target emulation if nothing is passed in ("-m" overrides this +# environment variable). Ensures we never blindly fallback on targeting the host +# platform. +: ${LDEMULATION:=@emulation@} + +# Three tasks: +# +# 1. Find all -L... switches for rpath +# +# 2. Find relocatable flag for build id. +# +# 3. Choose 32-bit dynamic linker if needed +declare -a libDirs +declare -A libs +declare -i relocatable=0 link32=0 + +if + [ "$NIX_@infixSalt@_DONT_SET_RPATH" != 1 ] \ + || [ "$NIX_@infixSalt@_SET_BUILD_ID" = 1 ] \ + || [ -e @out@/nix-support/dynamic-linker-m32 ] +then + prev= + # Old bash thinks empty arrays are undefined, ugh. + for p in \ + ${extraBefore+"${extraBefore[@]}"} \ + ${params+"${params[@]}"} \ + ${extraAfter+"${extraAfter[@]}"} + do + case "$prev" in + -L) + libDirs+=("$p") + ;; + -l) + libs["lib${p}.so"]=1 + ;; + -m) + # Presumably only the last `-m` flag has any effect. + case "$p" in + elf_i386) link32=1;; + *) link32=0;; + esac + ;; + -dynamic-linker | -plugin) + # Ignore this argument, or it will match *.so and be added to rpath. + ;; + *) + case "$p" in + -L/*) + libDirs+=("${p:2}") + ;; + -l?*) + libs["lib${p:2}.so"]=1 + ;; + "${NIX_STORE:-}"/*.so | "${NIX_STORE:-}"/*.so.*) + # This is a direct reference to a shared library. + libDirs+=("${p%/*}") + libs["${p##*/}"]=1 + ;; + -r | --relocatable | -i) + relocatable=1 + esac + ;; + esac + prev="$p" + done +fi + +if [ -e "@out@/nix-support/dynamic-linker-m32" ] && (( "$link32" )); then + # We have an alternate 32-bit linker and we're producing a 32-bit ELF, let's + # use it. + extraAfter+=( + '-dynamic-linker' + "$(< @out@/nix-support/dynamic-linker-m32)" + ) +fi + +# Add all used dynamic libraries to the rpath. +if [ "$NIX_@infixSalt@_DONT_SET_RPATH" != 1 ]; 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. + # It's important to add the rpath in the order of -L..., so + # the link time chosen objects will be those of runtime linking. + declare -A rpaths + for dir in ${libDirs+"${libDirs[@]}"}; do + if [[ "$dir" =~ [/.][/.] ]] && dir2=$(readlink -f "$dir"); then + dir="$dir2" + fi + if [ -n "${rpaths[$dir]:-}" ] || [[ "$dir" != "${NIX_STORE:-}"/* ]]; then + # If the path is not in the store, don't add it to the rpath. + # This typically happens for libraries in /tmp that are later + # copied to $out/lib. If not, we're screwed. + continue + fi + for path in "$dir"/*; do + file="${path##*/}" + if [ "${libs[$file]:-}" ]; then + # This library may have been provided by a previous directory, + # but if that library file is inside an output of the current + # derivation, it can be deleted after this compilation and + # should be found in a later directory, so we add all + # directories that contain any of the libraries to rpath. + rpaths["$dir"]=1 + extraAfter+=(-rpath "$dir") + break + fi + done + done + +fi + +# This is outside the DONT_SET_RPATH branch because it's more targeted and we +# usually want it (on Darwin) even if DONT_SET_RPATH is set. +if [ -n "${NIX_COREFOUNDATION_RPATH:-}" ]; then + extraAfter+=(-rpath $NIX_COREFOUNDATION_RPATH) +fi + +# Only add --build-id if this is a final link. FIXME: should build gcc +# with --enable-linker-build-id instead? +if [ "$NIX_@infixSalt@_SET_BUILD_ID" = 1 ] && ! (( "$relocatable" )); then + extraAfter+=(--build-id) +fi + + +# 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 + +PATH="$path_backup" +# Old bash workaround, see above. +exec @prog@ \ + ${extraBefore+"${extraBefore[@]}"} \ + ${params+"${params[@]}"} \ + ${extraAfter+"${extraAfter[@]}"} diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/macos-sierra-reexport-hack.bash b/nixpkgs/pkgs/build-support/bintools-wrapper/macos-sierra-reexport-hack.bash new file mode 100644 index 000000000000..71b9471cbc83 --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/macos-sierra-reexport-hack.bash @@ -0,0 +1,246 @@ +#! @shell@ + +set -eu -o pipefail + +# For cmd | while read; do ...; done +shopt -s lastpipe + +path_backup="$PATH" +if [ -n "@coreutils_bin@" ]; then + PATH="@coreutils_bin@/bin" +fi + +declare -ri recurThreshold=200 +declare -i overflowCount=0 + +declare -ar origArgs=("$@") + +# Throw away what we won't need +declare -a parentArgs=() + +while (( $# )); do + case "$1" in + -l) + echo "cctools LD does not support '-l foo'" >&2 + exit 1 + ;; + -lazy_library | -reexport_library | -upward_library | -weak_library) + overflowCount+=1 + shift 2 + ;; + -l* | *.so.* | *.dylib | -lazy-l* | -reexport-l* | -upward-l* | -weak-l*) + overflowCount+=1 + shift 1 + ;; + *.a | *.o) + shift 1 + ;; + -L | -F) + # Evidentally ld doesn't like using the child's RPATH, so it still + # needs these. + parentArgs+=("$1" "$2") + shift 2 + ;; + -L?* | -F?*) + parentArgs+=("$1") + shift 1 + ;; + -o) + outputName="$2" + parentArgs+=("$1" "$2") + shift 2 + ;; + -install_name | -dylib_install_name | -dynamic-linker | -plugin) + parentArgs+=("$1" "$2") + shift 2 + ;; + -rpath) + # Only an rpath to the child is needed, which we will add + shift 2 + ;; + *) + if [[ -f "$1" ]]; then + # Propabably a non-standard object file like Haskell's + # `.dyn_o`. Skip it like other inputs + : + else + parentArgs+=("$1") + fi + shift 1 + ;; + esac +done + + + +if (( "$overflowCount" <= "$recurThreshold" )); then + if [ -n "${NIX_DEBUG:-}" ]; then + echo "ld-wrapper: Only ${overflowCount} inputs counted while ${recurThreshold} is the ceiling, linking normally. " >&2 + fi + PATH="$path_backup" + exec @prog@ "${origArgs[@]}" +fi + + + +if [ -n "${NIX_DEBUG:-}" ]; then + echo "ld-wrapper: ${overflowCount} inputs counted when ${recurThreshold} is the ceiling, inspecting further. " >&2 +fi + +# Collect the normalized linker input +declare -a norm=() + +# Arguments are null-separated +@prog@ --dump-normalized-lib-args "${origArgs[@]}" | + while IFS= read -r -d '' input; do + norm+=("$input") + done + +declare -i leafCount=0 +declare lastLeaf='' +declare -a childrenInputs=() trailingInputs=() +while (( "${#norm[@]}" )); do + case "${norm[0]}" in + -lazy_library | -upward_library) + # TODO(@Ericson2314): Don't do that, but intersperse children + # between such args. + echo "ld-wrapper: Warning: Potentially changing link order" >&2 + trailingInputs+=("${norm[0]}" "${norm[1]}") + norm=("${norm[@]:2}") + ;; + -reexport_library | -weak_library) + childrenInputs+=("${norm[0]}" "${norm[1]}") + if [[ "${norm[1]}" != "$lastLeaf" ]]; then + leafCount+=1 + lastLeaf="${norm[1]}" + fi + norm=("${norm[@]:2}") + ;; + *.so | *.dylib) + childrenInputs+=(-reexport_library "${norm[0]}") + if [[ "${norm[0]}" != "$lastLeaf" ]]; then + leafCount+=1 + lastLeaf="${norm[0]}" + fi + norm=("${norm[@]:1}") + ;; + *.o | *.a) + # Don't delegate object files or static libs + parentArgs+=("${norm[0]}") + norm=("${norm[@]:1}") + ;; + *) + if [[ -f "${norm[0]}" ]]; then + # Propabably a non-standard object file. We'll let it by. + parentArgs+=("${norm[0]}") + norm=("${norm[@]:1}") + else + echo "ld-wrapper: Internal Error: Invalid normalized argument" >&2 + exit -1 + fi + ;; + esac +done + + + +if (( "$leafCount" <= "$recurThreshold" )); then + if [ -n "${NIX_DEBUG:-}" ]; then + echo "ld-wrapper: Only ${leafCount} *dynamic* inputs counted while ${recurThreshold} is the ceiling, linking normally. " >&2 + fi + PATH="$path_backup" + exec @prog@ "${origArgs[@]}" +fi + + + +if [ -n "${NIX_DEBUG:-}" ]; then + echo "ld-wrapper: ${leafCount} *dynamic* inputs counted when ${recurThreshold} is the ceiling, delegating to children. " >&2 +fi + +declare -r outputNameLibless=$( \ + if [[ -z "${outputName:+isUndefined}" ]]; then + echo unnamed + return 0; + fi + baseName=$(basename ${outputName}) + if [[ "$baseName" = lib* ]]; then + baseName="${baseName:3}" + fi + echo "$baseName") + +declare -ra children=( + "$outputNameLibless-reexport-delegate-0" + "$outputNameLibless-reexport-delegate-1" +) + +mkdir -p "$out/lib" + +symbolBloatObject=$outputNameLibless-symbol-hack.o +if [[ ! -f $symbolBloatObject ]]; then + # `-Q` means use GNU Assembler rather than Clang, avoiding an awkward + # dependency cycle. + printf '.private_extern _______child_hack_foo\nchild_hack_foo:\n' | + PATH="$PATH:@out@/bin" @targetPrefix@as -Q -- -o $symbolBloatObject +fi + +# Split inputs between children +declare -a child0Inputs=() child1Inputs=("${childrenInputs[@]}") +let "countFirstChild = $leafCount / 2" || true +lastLeaf='' +while (( "$countFirstChild" )); do + case "${child1Inputs[0]}" in + -reexport_library | -weak_library) + child0Inputs+=("${child1Inputs[0]}" "${child1Inputs[1]}") + if [[ "${child1Inputs[1]}" != "$lastLeaf" ]]; then + let countFirstChild-=1 || true + lastLeaf="${child1Inputs[1]}" + fi + child1Inputs=("${child1Inputs[@]:2}") + ;; + *.so | *.dylib) + child0Inputs+=(-reexport_library "${child1Inputs[0]}") + if [[ "${child1Inputs[0]}" != "$lastLeaf" ]]; then + let countFirstChild-=1 || true + lastLeaf="${child1Inputs[1]}" + fi + child1Inputs=("${child1Inputs[@]:2}") + ;; + *) + echo "ld-wrapper: Internal Error: Invalid delegated input" >&2 + exit -1 + ;; + esac +done + + +# First half of libs +@out@/bin/@targetPrefix@ld \ + -macosx_version_min $MACOSX_DEPLOYMENT_TARGET -arch x86_64 -dylib \ + -o "$out/lib/lib${children[0]}.dylib" \ + -install_name "$out/lib/lib${children[0]}.dylib" \ + "$symbolBloatObject" "${child0Inputs[@]}" "${trailingInputs[@]}" + +# Second half of libs +@out@/bin/@targetPrefix@ld \ + -macosx_version_min $MACOSX_DEPLOYMENT_TARGET -arch x86_64 -dylib \ + -o "$out/lib/lib${children[1]}.dylib" \ + -install_name "$out/lib/lib${children[1]}.dylib" \ + "$symbolBloatObject" "${child1Inputs[@]}" "${trailingInputs[@]}" + +parentArgs+=("-L$out/lib" -rpath "$out/lib") +if [[ $outputName != *reexport-delegate* ]]; then + parentArgs+=("-l${children[0]}" "-l${children[1]}") +else + parentArgs+=("-reexport-l${children[0]}" "-reexport-l${children[1]}") +fi + +parentArgs+=("${trailingInputs[@]}") + +if [ -n "${NIX_DEBUG:-}" ]; then + echo "flags using delegated children to @prog@:" >&2 + printf " %q\n" "${parentArgs[@]}" >&2 +fi + +PATH="$path_backup" +exec @prog@ "${parentArgs[@]}" diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/setup-hook.sh b/nixpkgs/pkgs/build-support/bintools-wrapper/setup-hook.sh new file mode 100644 index 000000000000..f65b792485a0 --- /dev/null +++ b/nixpkgs/pkgs/build-support/bintools-wrapper/setup-hook.sh @@ -0,0 +1,76 @@ +# Binutils Wrapper hygiene +# +# See comments in cc-wrapper's setup hook. This works exactly the same way. + +set -u + +# Skip setup hook if we're neither a build-time dep, nor, temporarily, doing a +# native compile. +# +# TODO(@Ericson2314): No native exception +[[ -z ${strictDeps-} ]] || (( "$hostOffset" < 0 )) || return 0 + +bintoolsWrapper_addLDVars () { + # See ../setup-hooks/role.bash + local role_post role_pre + getHostRoleEnvHook + + if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then + export NIX_${role_pre}LDFLAGS+=" -L$1/lib64" + fi + + if [[ -d "$1/lib" ]]; then + # Don't add the /lib directory if it actually doesn't contain any libraries. For instance, + # Python and Haskell packages often only have directories like $out/lib/ghc-8.4.3/ or + # $out/lib/python3.6/, so having them in LDFLAGS just makes the linker search unnecessary + # directories and bloats the size of the environment variable space. + if [[ -n "$(echo $1/lib/lib*)" ]]; then + export NIX_${role_pre}LDFLAGS+=" -L$1/lib" + fi + fi +} + +# See ../setup-hooks/role.bash +getTargetRole +getTargetRoleWrapper + +addEnvHooks "$targetOffset" bintoolsWrapper_addLDVars + +# shellcheck disable=SC2157 +if [ -n "@bintools_bin@" ]; then + addToSearchPath _PATH @bintools_bin@/bin +fi + +# shellcheck disable=SC2157 +if [ -n "@libc_bin@" ]; then + addToSearchPath _PATH @libc_bin@/bin +fi + +# shellcheck disable=SC2157 +if [ -n "@coreutils_bin@" ]; then + addToSearchPath _PATH @coreutils_bin@/bin +fi + +# Export tool environment variables so various build systems use the right ones. + +export NIX_${role_pre}BINTOOLS=@out@ + +for cmd in \ + ar as ld nm objcopy objdump readelf ranlib strip strings size windres +do + if + PATH=$_PATH type -p "@targetPrefix@${cmd}" > /dev/null + then + upper_case="$(echo "$cmd" | tr "[:lower:]" "[:upper:]")" + export "${role_pre}${upper_case}=@targetPrefix@${cmd}"; + export "${upper_case}${role_post}=@targetPrefix@${cmd}"; + fi +done + +# If unset, assume the default hardening flags. +: ${NIX_HARDENING_ENABLE="fortify stackprotector pic strictoverflow format relro bindnow"} +export NIX_HARDENING_ENABLE + +# No local scope in sourced file +unset -v role_pre role_post cmd upper_case +set +u |