summary refs log tree commit diff
path: root/pkgs
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2017-07-17 23:36:17 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2017-07-31 17:02:56 -0400
commit0c37778c2c17fb40407f6432ff009cd7ae5b17b1 (patch)
tree8e373e03d047490e92a725cb741b07b6701780b9 /pkgs
parentd4ef5ac0e962bd6604dda38617c4b98c77a62949 (diff)
downloadnixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.tar
nixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.tar.gz
nixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.tar.bz2
nixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.tar.lz
nixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.tar.xz
nixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.tar.zst
nixlib-0c37778c2c17fb40407f6432ff009cd7ae5b17b1.zip
cc-wrapper: WIP linking hack for mac OS
Probably best to override Haskell packages set, or anything else
linking a lot of libraries, with this.
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/build-support/cc-wrapper/default.nix20
-rw-r--r--pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.patch140
-rw-r--r--pkgs/stdenv/darwin/default.nix2
-rw-r--r--pkgs/test/macos-sierra-shared/default.nix43
-rw-r--r--pkgs/top-level/all-packages.nix6
5 files changed, 208 insertions, 3 deletions
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 { };