|
| 1 | +{ stdenv, buildPackages, ghc, lib, pkgconfig, writeText, runCommand |
| 2 | +, haskellLib, nonReinstallablePkgs, hsPkgs, setup-depends |
| 3 | +, package, name, src, flags }: |
| 4 | + |
| 5 | +let |
| 6 | + fullName = "${name}-setup"; |
| 7 | + |
| 8 | + flagsAndConfig = field: xs: lib.optionalString (xs != []) '' |
| 9 | + echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $out/configure-flags |
| 10 | + echo "${field}: ${lib.concatStringsSep " " xs}" >> $out/cabal.config |
| 11 | + ''; |
| 12 | + |
| 13 | + flatDepends = |
| 14 | + let |
| 15 | + makePairs = map (p: rec { key="${val}"; val=(p.components.library or p); }); |
| 16 | + closure = builtins.genericClosure { |
| 17 | + startSet = makePairs setup-depends; |
| 18 | + operator = {val,...}: makePairs val.config.depends; |
| 19 | + }; |
| 20 | + in map ({val,...}: val) closure; |
| 21 | + |
| 22 | + configFiles = runCommand "${fullName}-config" { nativeBuildInputs = [ghc]; } ('' |
| 23 | + mkdir -p $out |
| 24 | +
|
| 25 | + # Calls ghc-pkg for the target platform |
| 26 | + target-pkg() { |
| 27 | + ${ghc.targetPrefix}ghc-pkg "$@" |
| 28 | + } |
| 29 | +
|
| 30 | + target-pkg init $out/package.conf.d |
| 31 | +
|
| 32 | + # Copy over the nonReinstallablePkgs from the global package db. |
| 33 | + # Note: we need to use --global-package-db with ghc-pkg to prevent it |
| 34 | + # from looking into the implicit global package db when registering the package. |
| 35 | + ${lib.concatMapStringsSep "\n" (p: '' |
| 36 | + target-pkg describe ${p} | target-pkg --force --global-package-db $out/package.conf.d register - || true |
| 37 | + '') nonReinstallablePkgs} |
| 38 | +
|
| 39 | + ${lib.concatMapStringsSep "\n" (p: '' |
| 40 | + target-pkg --package-db ${p}/package.conf.d dump | target-pkg --force --package-db $out/package.conf.d register - |
| 41 | + '') flatDepends} |
| 42 | +
|
| 43 | + # Note: we pass `clear` first to ensure that we never consult the implicit global package db. |
| 44 | + ${flagsAndConfig "package-db" ["clear" "$out/package.conf.d"]} |
| 45 | +
|
| 46 | + echo ${lib.concatStringsSep " " (lib.mapAttrsToList (fname: val: "--flags=${lib.optionalString (!val) "-" + fname}") flags)} >> $out/configure-flags |
| 47 | +
|
| 48 | + '' |
| 49 | + # This code originates in the `generic-builder.nix` from nixpkgs. However GHC has been fixed |
| 50 | + # to drop unused libraries referneced from libraries; and this patch is usually included in the |
| 51 | + # nixpkgs's GHC builds. This doesn't sadly make this stupid hack unnecessary. It resurfes in |
| 52 | + # the form of Cabal trying to be smart. Cabal when linking a library figures out that you likely |
| 53 | + # need those `rpath` entries, and passes `-optl-Wl,-rpath,...` for each dynamic library path to |
| 54 | + # GHC, thus subverting the linker and forcing it to insert all those RPATHs weather or not they |
| 55 | + # are needed. We therfore reuse the linker hack here to move all al dynamic lirbaries into a |
| 56 | + # common folder (as links) and thus prevent Cabal from going nuts. |
| 57 | + # |
| 58 | + # TODO: Fix Cabal. |
| 59 | + # TODO: this is only needed if we do dynamic libraries. |
| 60 | + + lib.optionalString stdenv.isDarwin '' |
| 61 | + # Work around a limit in the macOS Sierra linker on the number of paths |
| 62 | + # referenced by any one dynamic library: |
| 63 | + # |
| 64 | + # Create a local directory with symlinks of the *.dylib (macOS shared |
| 65 | + # libraries) from all the dependencies. |
| 66 | + local dynamicLinksDir="$out/lib/links" |
| 67 | + mkdir -p $dynamicLinksDir |
| 68 | + for d in $(grep dynamic-library-dirs "$out/package.conf.d/"*|awk '{print $2}'|sort -u); do |
| 69 | + ln -s "$d/"*.dylib $dynamicLinksDir |
| 70 | + done |
| 71 | + # Edit the local package DB to reference the links directory. |
| 72 | + for f in "$out/package.conf.d/"*.conf; do |
| 73 | + sed -i "s,dynamic-library-dirs: .*,dynamic-library-dirs: $dynamicLinksDir," $f |
| 74 | + done |
| 75 | + '' + '' |
| 76 | + target-pkg --package-db $out/package.conf.d recache |
| 77 | + '' + '' |
| 78 | + target-pkg --package-db $out/package.conf.d check |
| 79 | + ''); |
| 80 | + |
| 81 | +in stdenv.lib.fix (drv: |
| 82 | + |
| 83 | +stdenv.mkDerivation { |
| 84 | + name = "${fullName}"; |
| 85 | + inherit src; |
| 86 | + nativeBuildInputs = [ghc]; |
| 87 | + |
| 88 | + CABAL_CONFIG = configFiles + /cabal.config; |
| 89 | + phases = ["unpackPhase" "buildPhase" "installPhase"]; |
| 90 | + buildPhase = '' |
| 91 | + for f in Setup.hs Setup.lhs; do |
| 92 | + if [ -f $f ]; then |
| 93 | + echo Compiling package $f |
| 94 | + ghc $f --make -o ./Setup |
| 95 | + setup=$(pwd)/Setup |
| 96 | + fi |
| 97 | + done |
| 98 | + [ -f ./Setup ] || (echo Failed to build Setup && exit 1) |
| 99 | + ''; |
| 100 | + |
| 101 | + installPhase = '' |
| 102 | + mkdir -p $out/bin |
| 103 | + install ./Setup $out/bin/Setup |
| 104 | + ''; |
| 105 | +}) |
| 106 | + |
| 107 | + |
0 commit comments