Skip to content

Commit d32d120

Browse files
committed
static-stack: Make it work with stack-1.9.1.
Works on stack commit f9d0042c141. The changes are necessary because stack-1.9.1 explicitly depends on Cabal-2.4.0.1 in its stack.yaml which is pulled in via stack2nix. Doing this, I also found that the way I patched Cabal so far was not really optimal, because not only for stack, but in general my patches for Cabal wouldn't be used if the Cabal version wasn't the default one in nixpkgs. Now instead I use patches instead of a Github fork so that they can be applied to any Cabal version. Also added is a framework for backwards compatibility in the situation that upstream Cabal starts merging my patches and they appear in nixpkgs. I've also checked that there's no regression to the set of all Stackage executables that can be built (#4) and added the non-working ones explicitly into the survey file.
1 parent 7d2b093 commit d32d120

File tree

1 file changed

+178
-44
lines changed

1 file changed

+178
-44
lines changed

survey/default.nix

Lines changed: 178 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ in
3030
overlays = overlays ++ [ (cython-disable-tests-overlay normalPkgs) ];
3131
}).pkgsMusl,
3232

33+
# When changing this, also change the default version of Cabal declared below
3334
compiler ? "ghc843",
3435

36+
defaultCabalPackageVersionComingWithGhc ? "Cabal_2_2_0_1",
37+
3538
normalHaskellPackages ?
3639
if integer-simple
3740
# Note we don't have to set the `-finteger-simple` flag for packages that GHC
@@ -213,37 +216,123 @@ let
213216
stackageExecutablesSet = keySet (builtins.attrNames stackageExecutables);
214217
isStackageExecutable = name: builtins.hasAttr name stackageExecutablesSet;
215218

216-
217219
# Cherry-picking cabal fixes
218220

219-
# TODO Remove this when these fixes are available in nixpkgs:
220-
# https://github.com/haskell/cabal/pull/5356 (-L flag deduplication)
221-
# https://github.com/haskell/cabal/pull/5446 (--enable-executable-static)
222-
# https://github.com/haskell/cabal/pull/5451 (ld-option passthrough)
223-
224-
# TODO do this via patches instead
225-
cabal_patched_src = pkgs.fetchFromGitHub {
226-
owner = "nh2";
227-
repo = "cabal";
228-
rev = "b66be72db3b34ea63144b45fcaf61822e0fade87";
229-
sha256 = "030f785a60fv0h6yqb6fmz1092nwczd0dbvnnsn6gvjs22rj39hc";
230-
};
231-
232-
Cabal_patched_Cabal_subdir = pkgs.stdenv.mkDerivation {
233-
name = "cabal-dedupe-src";
234-
buildCommand = ''
235-
cp -rv ${cabal_patched_src}/Cabal/ $out
236-
'';
237-
};
238-
239-
Cabal_patched = normalHaskellPackages.callCabal2nix "Cabal" Cabal_patched_Cabal_subdir {};
221+
# Note:
222+
# Be careful when changing any of the patches (both direct and
223+
# `file://` based), the above SHA might incorrectly cache it:
224+
# https://github.com/NixOS/nixpkgs/issues/48567
225+
# You may have to arbitrarily change the SHAs to see your changes
226+
# reflected.
227+
# TODO: Work around this by using `runCommand` or similar on a
228+
# plain fetchpatch, invoking `filterdiff` directly.
229+
makeCabalPatch = { name, url, fetchedSha256, processedSha256 }:
230+
let
231+
patchOnCabalLibraryFilesOnly = pkgs.fetchpatch {
232+
name = "${name}-Cabal-files-only";
233+
inherit url;
234+
sha256 = fetchedSha256;
235+
includes = ["Cabal/*"]; # Note `fetchpatch`'s `filterdiff` invocation runs with `-p1` as of writing
236+
excludes = ["Cabal/ChangeLog.md"]; # Changelog files almost always conflict
237+
};
238+
in
239+
pkgs.fetchpatch {
240+
inherit name;
241+
url = "file://${patchOnCabalLibraryFilesOnly}";
242+
sha256 = processedSha256;
243+
stripLen = 2; # strips of `a/Cabal/` (the nix derivation is already built from this subdir)
244+
extraPrefix = "";
245+
};
240246

241-
useFixedCabal = drv: pkgs.haskell.lib.overrideCabal drv (old: {
242-
setupHaskellDepends = (old.setupHaskellDepends or []) ++ [ Cabal_patched ];
243-
# TODO Check if this is necessary
244-
libraryHaskellDepends = (old.libraryHaskellDepends or []) ++ [ Cabal_patched ];
247+
applyPatchesToCabalDrv = cabalDrv: pkgs.haskell.lib.overrideCabal cabalDrv (old: {
248+
patches =
249+
# Patches we know are merged in a certain cabal version
250+
# (we include them conditionally here anyway, for the case
251+
# that the user specifies a different Cabal version e.g. via
252+
# `stack2nix`):
253+
(builtins.concatLists [
254+
# -L flag deduplication
255+
# https://github.com/haskell/cabal/pull/5356
256+
(lib.optional (pkgs.lib.versionOlder cabalDrv.version "2.4.0.0") (makeCabalPatch {
257+
name = "5356.patch";
258+
url = "https://github.com/haskell/cabal/commit/fd6ff29e268063f8a5135b06aed35856b87dd991.patch";
259+
fetchedSha256 = "1sklr5ckwllmhzy0hjk284a4n5wad70si9wnqaqc5i7m9jzpg2w2";
260+
processedSha256 = "10qxqshkv044d4s547gxhwwnn4d1bbq52g70nhsfjgpnj1d0qc2r";
261+
}))
262+
# Patches that as of writing aren't merged yet:
263+
]) ++ [
264+
# TODO Move this into the above section when merged in some Cabal version:
265+
# --enable-executable-static
266+
# https://github.com/haskell/cabal/pull/5446
267+
(if pkgs.lib.versionOlder cabalDrv.version "2.4.0.0"
268+
then
269+
# Older cabal, from https://github.com/nh2/cabal/commits/dedupe-more-include-and-linker-flags-enable-static-executables-flag-pass-ld-options-to-ghc-Cabal-v2.2.0.1
270+
(makeCabalPatch {
271+
name = "5446.patch";
272+
url = "https://github.com/haskell/cabal/commit/748f07b50724f2618798d200894f387020afc300.patch";
273+
fetchedSha256 = "1zmbalkdbd1xyf0kw5js74bpifhzhm16c98kn7kkgrwql1pbdyp5";
274+
processedSha256 = "0a726x2jkcmid0nynfhh6klgx4yb1igvjrmgnlxwchddqvyzcx86";
275+
})
276+
else
277+
(makeCabalPatch {
278+
name = "5446.patch";
279+
url = "https://github.com/haskell/cabal/commit/cb221c23c274f79dcab65aef3756377af113ae21.patch";
280+
fetchedSha256 = "1jfj9la2xgw8b9shqq82ffqa855ghp2ink30m7wvlxk5n1nl0jy9";
281+
processedSha256 = "0mpbia4dml52j5mjgyybl64czg470x8rqx0l9ap878sk09ikkgs5";
282+
})
283+
)
284+
# TODO Move this into the above section when merged in some Cabal version:
285+
# ld-option passthrough
286+
# https://github.com/haskell/cabal/pull/5451
287+
(if pkgs.lib.versionOlder cabalDrv.version "2.4.0.0"
288+
then
289+
# Older cabal, from https://github.com/nh2/cabal/commits/dedupe-more-include-and-linker-flags-enable-static-executables-flag-pass-ld-options-to-ghc-Cabal-v2.2.0.1
290+
(makeCabalPatch {
291+
name = "5451.patch";
292+
url = "https://github.com/haskell/cabal/commit/b66be72db3b34ea63144b45fcaf61822e0fade87.patch";
293+
fetchedSha256 = "0hndkfb96ry925xzx85km8y8pfv5ka5jz3jvy3m4l23jsrsd06c9";
294+
processedSha256 = "0ci7ch6csgm9282qh9pdypz6gzwwv8j0vlyfa8135zd8zpdx2zsw";
295+
})
296+
else
297+
(makeCabalPatch {
298+
name = "5451.patch";
299+
url = "https://github.com/haskell/cabal/commit/0aeb541393c0fce6099ea7b0366c956e18937791.patch";
300+
fetchedSha256 = "0pa9r79730n1kah8x54jrd6zraahri21jahasn7k4ng30rnnidgz";
301+
processedSha256 = "1x1rgr9psrsrm73ml0gla89x6x5wfizv99579j43daqib0ivhr71";
302+
})
303+
)
304+
];
245305
});
246306

307+
useFixedCabal =
308+
let
309+
patchIfCabal = drv:
310+
if (drv.pname or "") == "Cabal" # the `ghc` package has not `pname` attribute, so we default to "" here
311+
then applyPatchesToCabalDrv drv
312+
else drv;
313+
patchCabalInPackageList = drvs:
314+
let
315+
# Packages that come with the GHC version used have
316+
# `null` as their derivation (e.g. `text` or `Cabal`
317+
# if they are not overridden). We filter them out here.
318+
nonNullPackageList = builtins.filter (drv: !(builtins.isNull drv)) drvs;
319+
in
320+
map patchIfCabal nonNullPackageList;
321+
in
322+
drv: pkgs.haskell.lib.overrideCabal drv (old: {
323+
# If the package already depends on some explicit version
324+
# of Cabal, patch it, so that it has --enable-executable-static.
325+
# If it doesn't (it depends on the version of Cabal that comes
326+
# with GHC instead), add the same version that comes with
327+
# that GHC, but with our patches.
328+
# Unfortunately we don't have the final package set at hand
329+
# here, so we use the `haskellPackagesWithLibsReadyForStaticLinking`
330+
# one instead which has set `Cabal = ...` appropriately.
331+
setupHaskellDepends = patchCabalInPackageList (old.setupHaskellDepends or [haskellPackagesWithLibsReadyForStaticLinking.Cabal]);
332+
# TODO Check if this is necessary
333+
libraryHaskellDepends = patchCabalInPackageList (old.libraryHaskellDepends or [haskellPackagesWithLibsReadyForStaticLinking.Cabal]);
334+
});
335+
247336

248337
# Overriding system libraries that don't provide static libs
249338
# (`.a` files) by default
@@ -346,35 +435,31 @@ let
346435
});
347436
in {
348437

438+
Cabal =
439+
# If null, super.Cabal is a non-overriden package coming with GHC.
440+
# In that case, we can't patch it (we can't add patches to derivations that are null).
441+
# So we need to instead add a not-with-GHC Cabal package and patch that.
442+
# The best choice for that is the version that comes with the GHC.
443+
# Unfortunately we can't query that easily, so we maintain that manually
444+
# in `defaultCabalPackageVersionComingWithGhc`.
445+
# That effort will go away once all our Cabal patches are upstreamed.
446+
if builtins.isNull super.Cabal
447+
then applyPatchesToCabalDrv pkgs.haskell.packages."${compiler}"."${defaultCabalPackageVersionComingWithGhc}"
448+
else applyPatchesToCabalDrv super.Cabal;
449+
349450
# Helpers for other packages
350451

351452
hpc-coveralls = appendPatch super.hpc-coveralls (builtins.fetchurl https://github.com/guillaume-nargeot/hpc-coveralls/pull/73/commits/344217f513b7adfb9037f73026f5d928be98d07f.patch);
352453
persistent-sqlite = super.persistent-sqlite.override { sqlite = sqlite_static; };
353454
lzma = super.lzma.override { lzma = lzma_static; };
354455

355-
# If we `useFixedCabal` on stack, we also need to use the
356-
# it on hpack and hackage-security because otherwise
357-
# stack depends on 2 different versions of Cabal.
358-
hpack = useFixedCabal super.hpack;
359-
hackage-security = useFixedCabal super.hackage-security;
456+
hpack = super.hpack;
457+
hackage-security = super.hackage-security;
360458

361459
# See https://github.com/hslua/hslua/issues/67
362460
# It's not clear if it's safe to disable this as key functionality may be broken
363461
hslua = dontCheck super.hslua;
364462

365-
hsyslog = useFixedCabal super.hsyslog;
366-
367-
# Without this, when compiling `hsyslog`, GHC sees 2 Cabal
368-
# libraries, the unfixed one provided by cabal-doctest
369-
# (which is GHC's global unfixed one), and the fixed one as declared
370-
# for `hsyslog` through statify.
371-
# GHC does NOT issue a warning in that case, but just silently
372-
# picks the one from the global package database (the one
373-
# cabal-doctest would want), instead of the one from our
374-
# `useFixedCabal` one which is given on the command line at
375-
# https://github.com/NixOS/nixpkgs/blob/e7e5aaa0b9/pkgs/development/haskell-modules/generic-builder.nix#L330
376-
cabal-doctest = useFixedCabal super.cabal-doctest;
377-
378463
darcs =
379464
addStaticLinkerFlagsWithPkgconfig
380465
(super.darcs.override { curl = curl_static; })
@@ -551,6 +636,13 @@ let
551636

552637
});
553638

639+
# We have to use `useFixedCabal` here, and cannot just rely on the
640+
# "Cabal = ..." we override up in `haskellPackagesWithLibsReadyForStaticLinking`,
641+
# because that `Cabal` isn't used in all packages:
642+
# If a package doesn't explicitly depend on the `Cabal` package, then
643+
# for compiling its `Setup.hs` the Cabal package that comes with GHC
644+
# (that is in the default GHC package DB) is used instead, which
645+
# obviously doesn' thave our patches.
554646
statify = drv: with pkgs.haskell.lib; pkgs.lib.foldl appendConfigureFlag (disableLibraryProfiling (disableSharedExecutables (useFixedCabal drv))) [
555647
# "--ghc-option=-fPIC"
556648
"--enable-executable-static" # requires `useFixedCabal`
@@ -614,6 +706,48 @@ in
614706
allStackageExecutables =
615707
lib.filterAttrs (name: x: isStackageExecutable name) haskellPackages;
616708

709+
workingStackageExecutables =
710+
builtins.removeAttrs allStackageExecutables [
711+
# List of executables that don't work for reasons not yet investigated.
712+
# When changing this file, we should always check if this list grows or shrinks.
713+
"Agda"
714+
"Allure"
715+
"ALUT"
716+
"clash-ghc"
717+
"credential-store"
718+
"csg"
719+
"debug"
720+
"diagrams-builder"
721+
"dotenv"
722+
"ersatz"
723+
"filter-logger"
724+
"gtk3"
725+
"hamilton"
726+
"haskell-gi"
727+
"hquantlib"
728+
"ihaskell"
729+
"ipython-kernel"
730+
"jack"
731+
"LambdaHack"
732+
"language-puppet"
733+
"learn-physics"
734+
"lens-regex"
735+
"leveldb-haskell"
736+
"microformats2-parser"
737+
"mmark-cli"
738+
"odbc"
739+
"OpenAL"
740+
"rasterific-svg"
741+
"sdl2"
742+
"sdl2-gfx"
743+
"sdl2-image"
744+
"sdl2-mixer"
745+
"sdl2-ttf"
746+
"soxlib"
747+
"yesod-paginator"
748+
"yoga"
749+
"zeromq4-patterns"
750+
];
617751

618752
inherit normalPkgs;
619753
inherit pkgs;

0 commit comments

Comments
 (0)