diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix index 676fbd006881..c178204f9fb5 100644 --- a/pkgs/build-support/cc-wrapper/default.nix +++ b/pkgs/build-support/cc-wrapper/default.nix @@ -12,6 +12,7 @@ , isGNU ? false, isClang ? cc.isClang or false, gnugrep ? null , buildPackages ? {}, hostPlatform, targetPlatform , runCommand ? null +, useMacosReexportHack ? false }: with stdenv.lib; @@ -295,7 +296,20 @@ stdenv.mkDerivation { ln -s $ldPath/${prefix}as $out/bin/${prefix}as fi - wrap ${prefix}ld ${preWrap ./ld-wrapper.sh} ''${ld:-$ldPath/${prefix}ld} + wrap ${prefix}ld ${if !useMacosReexportHack + then preWrap ./ld-wrapper.sh + else stdenv.mkDerivation { + name = "patched-ld-wrapper-src"; + patches = [ ./macos-sierra-reexport-hack.patch ]; + unpackPhase = '' + src=$PWD + cp ${./ld-wrapper.sh} ld-wrapper.sh + ''; + buildPhase = ""; + installPhase = '' + cp ld-wrapper.sh $out + ''; + }} ''${ld:-$ldPath/${prefix}ld} if [ -e ${binutils_bin}/bin/${prefix}ld.gold ]; then wrap ${prefix}ld.gold ${preWrap ./ld-wrapper.sh} ${binutils_bin}/bin/${prefix}ld.gold @@ -399,5 +413,7 @@ stdenv.mkDerivation { { description = stdenv.lib.attrByPath ["meta" "description"] "System C compiler" cc_ + " (wrapper script)"; - }; + } // optionalAttrs useMacosReexportHack { + platforms = stdenv.lib.platforms.darwin; + }; } diff --git a/pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.patch b/pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.patch new file mode 100644 index 000000000000..031c5640f541 --- /dev/null +++ b/pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.patch @@ -0,0 +1,140 @@ +--- a/ld-wrapper.sh ++++ b/ld-wrapper.sh +@@ -101,35 +101,115 @@ if [ "$NIX_DONT_SET_RPATH" != 1 ]; then + rpath="" + + # First, find all -L... switches. +- allParams=("${params[@]}" ${extra[@]}) ++ declare -ar allParams=("${extraBefore[@]}" "${params[@]}" "${extra[@]}") ++ declare -a allParamsPost=() childrenLookup=() childrenLink=() ++ ++ declare -r recurThreshold=300 ++ ++ declare overflowCount=0 ++ for p in "${allParams[@]}"; do ++ case "$p" in ++ -o) ++ declare -r outputName="$p2" ++ ;; ++ (-l*) ++ let overflowCount+=1 ++ ;; ++ *) ;; ++ esac ++ done ++ ++ if (( "$overflowCount" > "$recurThreshold" )); then ++ declare -r linkIndirect="1" ++ else ++ declare -r linkIndirect="" ++ fi ++ ++ function append_Ls() { ++ if [[ -n "$linkIndirect" ]]; then ++ childrenLookup+=("$@") ++ fi ++ allParamsPost+=("$@") ++ } ++ ++ function append_ls() { ++ local p ++ if (( $# == 2 )); then p="$2"; else p="${1:2}"; fi ++ if [[ -n "$linkIndirect" && "$p" != "-lto_library" && "$p" != "-lSystem" ]]; then ++ childrenLink+=("$@") ++ else ++ allParamsPost+=("$@") ++ fi ++ } ++ + n=0 + while [ $n -lt ${#allParams[*]} ]; do + p=${allParams[n]} + p2=${allParams[$((n+1))]} ++ + if [ "${p:0:3}" = -L/ ]; then + addToLibPath ${p:2} ++ append_Ls "$p" + elif [ "$p" = -L ]; then + addToLibPath ${p2} ++ append_Ls "$p" "$p2" + n=$((n + 1)) + elif [ "$p" = -l ]; then + addToLibs ${p2} ++ append_ls "$p" "$p2" + n=$((n + 1)) + elif [ "${p:0:2}" = -l ]; then + addToLibs ${p:2} ++ append_ls "$p" + elif [ "$p" = -dynamic-linker ]; then + # Ignore the dynamic linker argument, or it + # will get into the next 'elif'. We don't want + # the dynamic linker path rpath to go always first. ++ allParamsPost+=("$p" "$p2") + n=$((n + 1)) + elif [[ "$p" =~ ^[^-].*\.so($|\.) ]]; then + # This is a direct reference to a shared library, so add + # its directory to the rpath. + path="$(dirname "$p")"; + addToRPath "${path}" ++ allParamsPost+=("$p") ++ else ++ allParamsPost+=("$p") + fi ++ + n=$((n + 1)) + done + ++ if [[ "$linkIndirect" ]]; then ++ while (( $n < "${#childrenLink[@]}" )); do ++ childrenLink[n]="-reexport${childrenLink[n]}" ++ done ++ declare -r outputNameLibless=$(basename $( ++ if [[ "${outputName:0:3}" = lib ]]; then ++ echo "${outputName:3}" ++ else ++ echo "${outputName:-unnamed}" ++ fi)) ++ declare -ra children=("$outputNameLibless-reexport-delegate-0" \ ++ "$outputNameLibless-reexport-delegate-1") ++ ++ mkdir -p "$out/lib" ++ ++ # first half of libs ++ "$0" -dylib -o "$out/lib/lib${children[0]}.dylib" \ ++ -install_name "$out/lib/lib${children[0]}.dylib" \ ++ "${childrenLookup[@]}" \ ++ "${childrenLink[@]::$((${#childrenLink[@]} / 2 ))}" ++ ++ # second half of libs ++ "$0" -dylib -o "$out/lib/lib${children[1]}.dylib" \ ++ -install_name "$out/lib/lib${children[1]}.dylib" \ ++ "${childrenLookup[@]}" \ ++ "${childrenLink[@]:$((${#childrenLink[@]} / 2 ))}" ++ ++ allParamsPost+=("-L$out/lib" "-l${children[0]}" "-l${children[1]}") ++ fi ++ + # Second, 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. +@@ -170,12 +243,8 @@ fi + + # Optionally print debug info. + if [ -n "$NIX_DEBUG" ]; then +- echo "original flags to @prog@:" >&2 +- for i in "${params[@]}"; do +- echo " $i" >&2 +- done +- echo "extra flags to @prog@:" >&2 +- for i in ${extra[@]}; do ++ echo "flags to @prog@:" >&2 ++ for i in "${allParamsPost[@]}"; do + echo " $i" >&2 + done + fi +@@ -185,4 +254,4 @@ if [ -n "$NIX_LD_WRAPPER_EXEC_HOOK" ]; then + fi + + PATH="$path_backup" +-exec @prog@ ${extraBefore[@]} "${params[@]}" ${extra[@]} ++exec @prog@ "${allParamsPost[@]}" diff --git a/pkgs/stdenv/darwin/default.nix b/pkgs/stdenv/darwin/default.nix index f6d9bcac5104..ed114fa740c8 100644 --- a/pkgs/stdenv/darwin/default.nix +++ b/pkgs/stdenv/darwin/default.nix @@ -297,7 +297,7 @@ in rec { initialPath = import ../common-path.nix { inherit pkgs; }; shell = "${pkgs.bash}/bin/bash"; - cc = import ../../build-support/cc-wrapper { + cc = lib.callPackageWith {} ../../build-support/cc-wrapper { inherit (pkgs) stdenv; inherit shell; nativeTools = false; diff --git a/pkgs/test/macos-sierra-shared/default.nix b/pkgs/test/macos-sierra-shared/default.nix new file mode 100644 index 000000000000..8d7b9fc93842 --- /dev/null +++ b/pkgs/test/macos-sierra-shared/default.nix @@ -0,0 +1,43 @@ +{ lib, clangStdenv, clang-sierraHack-stdenv }: + +let + makeBigExe = stdenv: prefix: rec { + + sillyLibs = lib.genList (i: stdenv.mkDerivation rec { + name = "${prefix}-fluff-${toString i}"; + unpackPhase = '' + src=$PWD + echo 'int asdf${toString i}(void) { return ${toString i}; }' > ${name}.c + ''; + buildPhase = '' + $CC -shared ${name}.c -o lib${name}.dylib -Wl,-install_name,$out/lib/lib${name}.dylib + ''; + installPhase = '' + mkdir -p "$out/lib" + mv lib${name}.dylib "$out/lib" + ''; + }) 500 + ; + + finalExe = stdenv.mkDerivation rec { + name = "${prefix}-final-asdf"; + unpackPhase = '' + src=$PWD + echo 'int main(int argc, char **argv) { return argc; }' > main.c; + ''; + buildPhase = '' + $CC main.c ${toString (map (x: "-l${x.name}") sillyLibs)} -o asdf + ''; + buildInputs = sillyLibs; + installPhase = '' + mkdir -p "$out/bin" + mv asdf "$out/bin" + ''; + }; + + }; + +in { + good = makeBigExe clang-sierraHack-stdenv "good"; + bad = makeBigExe clangStdenv "bad"; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 7c26ba7c8263..85573b10321b 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -5162,6 +5162,11 @@ with pkgs; clang = llvmPackages.clang; + clang-sierraHack = clang.override { + name = "clang-wrapper-with-reexport-hack"; + useMacosReexportHack = true; + }; + clang_4 = llvmPackages_4.clang; clang_39 = llvmPackages_39.clang; clang_38 = llvmPackages_38.clang; @@ -5189,6 +5194,7 @@ with pkgs; #Use this instead of stdenv to build with clang clangStdenv = if stdenv.isDarwin then stdenv else lowPrio llvmPackages.stdenv; + clang-sierraHack-stdenv = overrideCC stdenv clang-sierraHack; libcxxStdenv = lowPrio llvmPackages.libcxxStdenv; clean = callPackage ../development/compilers/clean { };