Skip to content

Commit 341341c

Browse files
authored
Reduce cabalProject IFD deps using dummy GHCs (#607)
The `cabalProject` function works by running `cabal v2-configure` followed by `plan-to-nix`. However for `v2-configure` to correctly calculate the plan (including flag settings and buildable components) it needs to know what GHC we want to use. This causes significant problems: * For hydra to assemble a list of jobs from `components.tests` it must first have GHC that will be used. If a patch has been applied to the GHC to be used it must be rebuilt before the list of jobs can be assembled. If a lot of different GHCs are being tests that can be a lot of work all happening in the eval stage where little feedback is available. * Once the jobs are running the compilation of the GHC needed (the eval stage already must have done it, but the outputs there are apparently not added to the cache) happens inside the IFD part of `cabalProject`. This causes a very large amount of work to be done in the IFD and our understanding is that this can cause problems on nix and/or hydra. * When using `cabalProject` we cannot examine the properties of the project without building or downloading the GHC (less of an issue as we would normally need it soon anyway). The solution here is to: * Create a dummy `ghc` and `ghc-pkg` from the real ones by capturing the `ghc` and `ghc-pkg` outputs that `cabal v2-configure` requests. * The dummy `ghc` and `ghc-pkg` is used instead of the real one in `cabalProject` when running `cabal v2-configure`. * The captured outputs are materialized into the haskell.nix repo so that the real GHC is only needed when `checkMaterialization` is set.
1 parent 5e644a4 commit 341341c

File tree

51 files changed

+17275
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+17275
-1
lines changed

lib/call-cabal-project-to-nix.nix

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,92 @@ let
187187
}
188188
else replaceSoureRepos rawCabalProject;
189189

190+
# The use of a the actual GHC can cause significant problems:
191+
# * For hydra to assemble a list of jobs from `components.tests` it must
192+
# first have GHC that will be used. If a patch has been applied to the
193+
# GHC to be used it must be rebuilt before the list of jobs can be assembled.
194+
# If a lot of different GHCs are being tests that can be a lot of work all
195+
# happening in the eval stage where little feedback is available.
196+
# * Once the jobs are running the compilation of the GHC needed (the eval
197+
# stage already must have done it, but the outputs there are apparently
198+
# not added to the cache) happens inside the IFD part of cabalProject.
199+
# This causes a very large amount of work to be done in the IFD and our
200+
# understanding is that this can cause problems on nix and/or hydra.
201+
# * When using cabalProject we cannot examine the properties of the project without
202+
# building or downloading the GHC (less of an issue as we would normally need
203+
# it soon anyway).
204+
#
205+
# The solution here is to capture the GHC outputs that `cabal v2-configure`
206+
# requests and materialize it so that the real GHC is only needed
207+
# when `checkMaterialization` is set.
208+
dummy-ghc-data = pkgs.haskell-nix.materialize ({
209+
sha256 = null;
210+
sha256Arg = "sha256";
211+
materialized = ../materialized/dummy-ghc + "/${ghc.targetPrefix}${ghc.name}-${pkgs.stdenv.buildPlatform.system}";
212+
reasonNotSafe = null;
213+
} // pkgs.lib.optionalAttrs (checkMaterialization != null) {
214+
inherit checkMaterialization;
215+
}) (
216+
runCommand ("dummy-data-" + ghc.name) {
217+
nativeBuildInputs = [ ghc ];
218+
} ''
219+
mkdir -p $out/ghc
220+
mkdir -p $out/ghc-pkg
221+
${ghc.targetPrefix}ghc --numeric-version > $out/ghc/numeric-version
222+
${ghc.targetPrefix}ghc --info | grep -v /nix/store > $out/ghc/info
223+
${ghc.targetPrefix}ghc --supported-languages > $out/ghc/supported-languages
224+
${ghc.targetPrefix}ghc-pkg --version > $out/ghc-pkg/version
225+
# The order of the `ghc-pkg dump` output seems to be non
226+
# deterministic so we need to sort it so that it is always
227+
# the same.
228+
# Sort the output by spliting it on the --- separator line,
229+
# sorting it, adding the --- separators back and removing the
230+
# last line (the trailing ---)
231+
${ghc.targetPrefix}ghc-pkg dump --global -v0 \
232+
| grep -v /nix/store \
233+
| grep -v '^abi:' \
234+
| tr '\n' '\r' \
235+
| sed -e 's/\r\r*/\r/g' \
236+
| sed -e 's/\r$//g' \
237+
| sed -e 's/\r---\r/\n/g' \
238+
| sort \
239+
| sed -e 's/$/\r---/g' \
240+
| tr '\r' '\n' \
241+
| sed -e '$ d' \
242+
> $out/ghc-pkg/dump-global
243+
'');
244+
245+
# Dummy `ghc` that uses the captured output
246+
dummy-ghc = pkgs.writeTextFile {
247+
name = "dummy-" + ghc.name;
248+
executable = true;
249+
destination = "/bin/${ghc.targetPrefix}ghc";
250+
text = ''
251+
if [ "'$*'" == "'--numeric-version'" ]; then cat ${dummy-ghc-data}/ghc/numeric-version;
252+
elif [ "'$*'" == "'--supported-languages'" ]; then cat ${dummy-ghc-data}/ghc/supported-languages;
253+
elif [ "'$*'" == "'--print-global-package-db'" ]; then echo $out/dumby-db;
254+
elif [ "'$*'" == "'--info'" ]; then cat ${dummy-ghc-data}/ghc/info;
255+
elif [ "'$*'" == "'--print-libdir'" ]; then echo ${dummy-ghc-data}/ghc/libdir;
256+
else
257+
false
258+
fi
259+
'';
260+
};
261+
262+
# Dummy `ghc-pkg` that uses the captured output
263+
dummy-ghc-pkg = pkgs.writeTextFile {
264+
name = "dummy-pkg-" + ghc.name;
265+
executable = true;
266+
destination = "/bin/${ghc.targetPrefix}ghc-pkg";
267+
text = ''
268+
if [ "'$*'" == "'--version'" ]; then cat ${dummy-ghc-data}/ghc-pkg/version;
269+
elif [ "'$*'" == "'dump --global -v0'" ]; then cat ${dummy-ghc-data}/ghc-pkg/dump-global;
270+
else
271+
false
272+
fi
273+
'';
274+
};
275+
190276
plan-nix = materialize ({
191277
inherit materialized;
192278
sha256 = plan-sha256;
@@ -199,7 +285,7 @@ let
199285
} // pkgs.lib.optionalAttrs (checkMaterialization != null) {
200286
inherit checkMaterialization;
201287
}) (runCommand (if name == null then "plan-to-nix-pkgs" else name + "-plan-to-nix-pkgs") {
202-
nativeBuildInputs = [ nix-tools ghc hpack cabal-install pkgs.rsync pkgs.git ];
288+
nativeBuildInputs = [ nix-tools dummy-ghc dummy-ghc-pkg hpack cabal-install pkgs.rsync ];
203289
# Needed or stack-to-nix will die on unicode inputs
204290
LOCALE_ARCHIVE = pkgs.lib.optionalString (pkgs.stdenv.hostPlatform.libc == "glibc") "${pkgs.glibcLocales}/lib/locale/locale-archive";
205291
LANG = "en_US.UTF-8";

0 commit comments

Comments
 (0)