Skip to content

Commit 7c6cae4

Browse files
committed
Add config.hsPkgs.shellFor function
I needed to rearrange a few things to write this function.
1 parent ff3b316 commit 7c6cae4

File tree

6 files changed

+282
-206
lines changed

6 files changed

+282
-206
lines changed

builder/comp-builder.nix

Lines changed: 5 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{ stdenv, buildPackages, ghc, lib, pkgconfig, writeText, runCommand, haskellLib, nonReinstallablePkgs, ghcForComponent, hsPkgs }:
1+
{ stdenv, buildPackages, ghc, lib, pkgconfig, haskellLib, makeConfigFiles, ghcForComponent, hsPkgs }:
22

33
{ componentId
44
, component
@@ -39,115 +39,10 @@ let
3939
then "${name}-all"
4040
else "${name}-${componentId.ctype}-${componentId.cname}";
4141

42-
flagsAndConfig = field: xs: lib.optionalString (xs != []) ''
43-
echo ${lib.concatStringsSep " " (map (x: "--${field}=${x}") xs)} >> $out/configure-flags
44-
echo "${field}: ${lib.concatStringsSep " " xs}" >> $out/cabal.config
45-
'';
46-
47-
flatDepends =
48-
let
49-
makePairs = map (p: rec { key="${val}"; val=(p.components.library or p); });
50-
closure = builtins.genericClosure {
51-
startSet = makePairs component.depends;
52-
operator = {val,...}: makePairs val.config.depends;
53-
};
54-
in map ({val,...}: val) closure;
55-
56-
exactDep = pdbArg: p: ''
57-
if id=$(target-pkg ${pdbArg} field ${p} id --simple-output); then
58-
echo "--dependency=${p}=$id" >> $out/configure-flags
59-
fi
60-
if ver=$(target-pkg ${pdbArg} field ${p} version --simple-output); then
61-
echo "constraint: ${p} == $ver" >> $out/cabal.config
62-
echo "constraint: ${p} installed" >> $out/cabal.config
63-
fi
64-
'';
65-
66-
envDep = pdbArg: p: ''
67-
if id=$(target-pkg ${pdbArg} field ${p} id --simple-output); then
68-
echo "package-id $id" >> $out/ghc-environment
69-
fi
70-
'';
71-
72-
configFiles = runCommand "${fullName}-config" { nativeBuildInputs = [ghc]; } (''
73-
mkdir -p $out
74-
75-
# Calls ghc-pkg for the target platform
76-
target-pkg() {
77-
${ghc.targetPrefix}ghc-pkg "$@"
78-
}
79-
80-
target-pkg init $out/package.conf.d
81-
82-
${lib.concatStringsSep "\n" (lib.mapAttrsToList flagsAndConfig {
83-
"extra-lib-dirs" = map (p: "${lib.getLib p}/lib") component.libs;
84-
"extra-include-dirs" = map (p: "${lib.getDev p}/include") component.libs;
85-
"extra-framework-dirs" = map (p: "${p}/Library/Frameworks") component.frameworks;
86-
})}
87-
88-
# Copy over the nonReinstallablePkgs from the global package db.
89-
# Note: we need to use --global-package-db with ghc-pkg to prevent it
90-
# from looking into the implicit global package db when registering the package.
91-
${lib.concatMapStringsSep "\n" (p: ''
92-
target-pkg describe ${p} | target-pkg --force --global-package-db $out/package.conf.d register - || true
93-
'') nonReinstallablePkgs}
94-
95-
${lib.concatMapStringsSep "\n" (p: ''
96-
target-pkg --package-db ${p}/package.conf.d dump | target-pkg --force --package-db $out/package.conf.d register -
97-
'') flatDepends}
98-
99-
# Note: we pass `clear` first to ensure that we never consult the implicit global package db.
100-
${flagsAndConfig "package-db" ["clear" "$out/package.conf.d"]}
101-
102-
echo ${lib.concatStringsSep " " (lib.mapAttrsToList (fname: val: "--flags=${lib.optionalString (!val) "-" + fname}") flags)} >> $out/configure-flags
103-
104-
# Provide a GHC environment file
105-
cat > $out/ghc-environment <<EOF
106-
package-db $out/package.conf.d
107-
EOF
108-
${lib.concatMapStringsSep "\n" (p: envDep "--package-db ${p.components.library or p}/package.conf.d" p.identifier.name) component.depends}
109-
${lib.concatMapStringsSep "\n" (envDep "") (lib.remove "ghc" nonReinstallablePkgs)}
110-
111-
'' + lib.optionalString component.doExactConfig ''
112-
echo "--exact-configuration" >> $out/configure-flags
113-
echo "allow-newer: ${package.identifier.name}:*" >> $out/cabal.config
114-
echo "allow-older: ${package.identifier.name}:*" >> $out/cabal.config
115-
116-
${lib.concatMapStringsSep "\n" (p: exactDep "--package-db ${p.components.library}/package.conf.d" p.identifier.name) component.depends}
117-
${lib.concatMapStringsSep "\n" (exactDep "") nonReinstallablePkgs}
118-
119-
''
120-
# This code originates in the `generic-builder.nix` from nixpkgs. However GHC has been fixed
121-
# to drop unused libraries referneced from libraries; and this patch is usually included in the
122-
# nixpkgs's GHC builds. This doesn't sadly make this stupid hack unnecessary. It resurfes in
123-
# the form of Cabal trying to be smart. Cabal when linking a library figures out that you likely
124-
# need those `rpath` entries, and passes `-optl-Wl,-rpath,...` for each dynamic library path to
125-
# GHC, thus subverting the linker and forcing it to insert all those RPATHs weather or not they
126-
# are needed. We therfore reuse the linker hack here to move all al dynamic lirbaries into a
127-
# common folder (as links) and thus prevent Cabal from going nuts.
128-
#
129-
# TODO: Fix Cabal.
130-
# TODO: this is only needed if we do dynamic libraries.
131-
+ lib.optionalString stdenv.isDarwin ''
132-
# Work around a limit in the macOS Sierra linker on the number of paths
133-
# referenced by any one dynamic library:
134-
#
135-
# Create a local directory with symlinks of the *.dylib (macOS shared
136-
# libraries) from all the dependencies.
137-
local dynamicLinksDir="$out/lib/links"
138-
mkdir -p $dynamicLinksDir
139-
for d in $(grep dynamic-library-dirs "$out/package.conf.d/"*|awk '{print $2}'|sort -u); do
140-
ln -s "$d/"*.dylib $dynamicLinksDir
141-
done
142-
# Edit the local package DB to reference the links directory.
143-
for f in "$out/package.conf.d/"*.conf; do
144-
sed -i "s,dynamic-library-dirs: .*,dynamic-library-dirs: $dynamicLinksDir," $f
145-
done
146-
'' + ''
147-
target-pkg --package-db $out/package.conf.d recache
148-
'' + ''
149-
target-pkg --package-db $out/package.conf.d check
150-
'');
42+
configFiles = makeConfigFiles {
43+
inherit (package) identifier;
44+
inherit component fullName flags;
45+
};
15146

15247
finalConfigureFlags = lib.concatStringsSep " " (
15348
[ "--prefix=$out"

builder/default.nix

Lines changed: 26 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,34 @@
1-
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, buildGHC, fetchurl, writeText, runCommand, pkgconfig, nonReinstallablePkgs, ghcForComponent, hsPkgs }:
2-
3-
{ flags
4-
, package
5-
, components
6-
, cabal-generator
7-
8-
, name
9-
, sha256
10-
, src
11-
, revision
12-
, revisionSha256
13-
, patches
14-
15-
, preUnpack
16-
, postUnpack
17-
, preConfigure
18-
, postConfigure
19-
, preBuild
20-
, postBuild
21-
, preCheck
22-
, postCheck
23-
, preInstall
24-
, postInstall
25-
, preHaddock
26-
, postHaddock
27-
28-
, shellHook
29-
30-
, ...
31-
}@config:
1+
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, buildGHC, fetchurl, pkgconfig, nonReinstallablePkgs, hsPkgs }:
322

333
let
34-
cabalFile = if revision == null || revision == 0 then null else
35-
fetchurl {
36-
name = "${name}-${toString revision}.cabal";
37-
url = "https://hackage.haskell.org/package/${name}/revision/${toString revision}.cabal";
38-
sha256 = revisionSha256;
39-
};
40-
41-
defaultSetupSrc = builtins.toFile "Setup.hs" ''
42-
import Distribution.Simple
43-
main = defaultMain
44-
'';
45-
defaultSetup = buildPackages.runCommand "default-Setup" { nativeBuildInputs = [buildGHC]; } ''
46-
cat ${defaultSetupSrc} > Setup.hs
47-
mkdir -p $out/bin
48-
${buildGHC.targetPrefix}ghc Setup.hs --make -o $out/bin/Setup
49-
'';
50-
51-
setup = if package.buildType == "Simple"
52-
then defaultSetup
53-
else stdenv.mkDerivation {
54-
name = "${name}-setup";
55-
nativeBuildInputs = [buildGHC];
56-
inherit src;
57-
phases = ["unpackPhase" "buildPhase" "installPhase"];
58-
buildPhase = ''
59-
for f in Setup.hs Setup.lhs; do
60-
if [ -f $f ]; then
61-
echo Compiling package $f
62-
ghc $f --make -o ./Setup
63-
setup=$(pwd)/Setup
64-
fi
65-
done
66-
[ -f ./Setup ] || (echo Failed to build Setup && exit 1)
67-
'';
68-
69-
installPhase = ''
70-
mkdir -p $out/bin
71-
install ./Setup $out/bin/Setup
72-
'';
73-
};
4+
# Builds a single component of a package.
5+
comp-builder = haskellLib.weakCallPackage pkgs ./comp-builder.nix {
6+
inherit ghc haskellLib makeConfigFiles ghcForComponent hsPkgs;
7+
};
748

75-
comp-builder = haskellLib.weakCallPackage pkgs ./comp-builder.nix { inherit ghc haskellLib nonReinstallablePkgs ghcForComponent hsPkgs; };
9+
# Wraps GHC to provide dependencies in a way that works for both the
10+
# component builder and for nix-shells.
11+
ghcForComponent = import ./ghc-for-component-wrapper.nix {
12+
inherit lib ghc;
13+
inherit (buildPackages) stdenv runCommand makeWrapper;
14+
inherit (buildPackages.xorg) lndir;
15+
};
7616

77-
buildComp = componentId: component: comp-builder {
78-
inherit componentId component package name src flags setup cabalFile cabal-generator patches revision
79-
preUnpack postUnpack preConfigure postConfigure
80-
preBuild postBuild preCheck postCheck
81-
preInstall postInstall preHaddock postHaddock
82-
shellHook
83-
;
17+
# Builds a derivation which contains a ghc package-db of
18+
# dependencies for a component.
19+
makeConfigFiles = haskellLib.weakCallPackage pkgs ./make-config-files.nix {
20+
inherit ghc haskellLib nonReinstallablePkgs;
8421
};
8522

8623
in {
87-
components = haskellLib.applyComponents buildComp config;
88-
inherit (package) identifier;
89-
inherit setup cabalFile;
90-
isHaskell = true;
24+
# Build a Haskell package from its config.
25+
# TODO: this pkgs is the adjusted pkgs, but pkgs.pkgs is unadjusted
26+
build-package = haskellLib.weakCallPackage pkgs ./hspkg-builder.nix {
27+
inherit haskellLib ghc buildGHC comp-builder;
28+
};
29+
30+
# Same as haskellPackages.shellFor in nixpkgs.
31+
shellFor = haskellLib.weakCallPackage pkgs ./shell-for.nix {
32+
inherit hsPkgs ghcForComponent makeConfigFiles;
33+
};
9134
}

builder/hspkg-builder.nix

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{ pkgs, buildPackages, stdenv, lib, haskellLib, ghc, buildGHC, fetchurl, runCommand, pkgconfig, comp-builder }:
2+
3+
4+
{ flags
5+
, package
6+
, components
7+
, cabal-generator
8+
9+
, name
10+
, sha256
11+
, src
12+
, revision
13+
, revisionSha256
14+
, patches
15+
16+
, preUnpack
17+
, postUnpack
18+
, preConfigure
19+
, postConfigure
20+
, preBuild
21+
, postBuild
22+
, preCheck
23+
, postCheck
24+
, preInstall
25+
, postInstall
26+
, preHaddock
27+
, postHaddock
28+
29+
, shellHook
30+
31+
, ...
32+
}@config:
33+
34+
let
35+
cabalFile = if revision == null || revision == 0 then null else
36+
fetchurl {
37+
name = "${name}-${toString revision}.cabal";
38+
url = "https://hackage.haskell.org/package/${name}/revision/${toString revision}.cabal";
39+
sha256 = revisionSha256;
40+
};
41+
42+
defaultSetupSrc = builtins.toFile "Setup.hs" ''
43+
import Distribution.Simple
44+
main = defaultMain
45+
'';
46+
defaultSetup = buildPackages.runCommand "default-Setup" { nativeBuildInputs = [buildGHC]; } ''
47+
cat ${defaultSetupSrc} > Setup.hs
48+
mkdir -p $out/bin
49+
${buildGHC.targetPrefix}ghc Setup.hs --make -o $out/bin/Setup
50+
'';
51+
52+
setup = if package.buildType == "Simple"
53+
then defaultSetup
54+
else stdenv.mkDerivation {
55+
name = "${name}-setup";
56+
nativeBuildInputs = [buildGHC];
57+
inherit src;
58+
phases = ["unpackPhase" "buildPhase" "installPhase"];
59+
buildPhase = ''
60+
for f in Setup.hs Setup.lhs; do
61+
if [ -f $f ]; then
62+
echo Compiling package $f
63+
ghc $f --make -o ./Setup
64+
setup=$(pwd)/Setup
65+
fi
66+
done
67+
[ -f ./Setup ] || (echo Failed to build Setup && exit 1)
68+
'';
69+
70+
installPhase = ''
71+
mkdir -p $out/bin
72+
install ./Setup $out/bin/Setup
73+
'';
74+
};
75+
76+
buildComp = componentId: component: comp-builder {
77+
inherit componentId component package name src flags setup cabalFile cabal-generator patches revision
78+
preUnpack postUnpack preConfigure postConfigure
79+
preBuild postBuild preCheck postCheck
80+
preInstall postInstall preHaddock postHaddock
81+
shellHook
82+
;
83+
};
84+
85+
in {
86+
components = haskellLib.applyComponents buildComp config;
87+
inherit (package) identifier;
88+
inherit setup cabalFile;
89+
isHaskell = true;
90+
}

0 commit comments

Comments
 (0)