Skip to content

haskellPackages.{ghcWithPackages, ghcWithHoogle}: make overrideable #146770

Merged
sternenseemann merged 3 commits intoNixOS:haskell-updatesfrom
sternenseemann:ghc-with-packages-overrideable
Jan 6, 2022
Merged

haskellPackages.{ghcWithPackages, ghcWithHoogle}: make overrideable #146770
sternenseemann merged 3 commits intoNixOS:haskell-updatesfrom
sternenseemann:ghc-with-packages-overrideable

Conversation

@sternenseemann
Copy link
Member

Motivation for this change

Make ghcWithPackages.override { withLLVM = true; } (p: [ ... ]) work.

Things done
  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 21.11 Release Notes (or backporting 21.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
    • (Release notes changes) Ran nixos/doc/manual/md-to-db.sh to update generated release notes
  • Fits CONTRIBUTING.md.

@github-actions github-actions bot added the 6.topic: haskell General-purpose, statically typed, purely functional programming language label Nov 20, 2021
@sternenseemann sternenseemann added the 9.needs: port to stable A PR needs a backport to the stable release. label Nov 22, 2021
@sternenseemann sternenseemann force-pushed the ghc-with-packages-overrideable branch from a6d26d6 to cffdd83 Compare November 23, 2021 15:35
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux. labels Nov 23, 2021
It's been quite a while since any version below that has been in use in
nixpkgs, so this check is almost certainly safe to remove.
Overrideable functions are possible by wrapping them as functors in an
attribute set first and appending the overrideScope and override
attributes later.
@sternenseemann sternenseemann force-pushed the ghc-with-packages-overrideable branch from cffdd83 to 10c9142 Compare November 25, 2021 20:24
@sternenseemann
Copy link
Member Author

sternenseemann commented Dec 14, 2021

A bit more detailed writeup concerning the how and why of this change, as asked for by @cdepillabout:

Basically, this allows to use override on ghcWithHoogle and ghcWithPackages as you'd expect from nixpkgs in general. The main benefit of this is that you can now add LLVM to a shell environment even if the used GHC is compiled without useLLVM enabled by using ghcWithPackages.override { useLLVM = true; }. It is then possible to use -fllvm which is sometimes useful when there's a bug in the native codegen backend, but LLVM works as expected.

To allow for this the following changes were made:

  • Change our custom callPackage wrapper (which adds overrideScope) to deal properly with functions by converting them into a functor set and appending the override* attributes.
  • Refactor withPackages so that it is no longer a wrapper function around with-packages-wrapper.nix, but instead this file does everything. This is crucial because the wrapper function hides the overrides from the user. For this, with-packages-wrapper.nix now takes the selectPackages function and the full haskellPackages as an input.
  • Move the hoogle wrapper functionality into with-packages-wrapper.nix as well, so ghcWithHoogle doesn't have to be a wrapper function that hides the overrides. For this the hoogle wrapper hoogle.nix is also exposed as its own attribute hoogleWithPackages which can be used and overridden independently (a nice bonus).

@maralorn
Copy link
Member

I won`t pretend I understand everything of this, but the change seems reasonable and wrappers still seem to be working.

@cdepillabout
Copy link
Member

cdepillabout commented Dec 22, 2021

@sternenseemann Thanks for writing up this explanation! I'm going to try to do a review of this. Sorry for taking a long time to get to this review?


Here's one thing that I don't think I can use GitHub's UI to comment on:

diff --git a/pkgs/development/haskell-modules/configuration-common.nix b/pkgs/development/haskell-modules/configuration-common.nix
index 87d1cef5857..802038d4fcb 100644
--- a/pkgs/development/haskell-modules/configuration-common.nix
+++ b/pkgs/development/haskell-modules/configuration-common.nix
@@ -44,6 +44,7 @@ self: super: {
   # enable using a local hoogle with extra packagages in the database
   # nix-shell -p "haskellPackages.hoogleLocal { packages = with haskellPackages; [ mtl lens ]; }"
   # $ hoogle server
+  # this is broken?
   hoogleLocal = { packages ? [] }: self.callPackage ./hoogle.nix { inherit packages; };
 
   # Needs older QuickCheck version

It looks like this hoogleLocal derivation is still passing packages to ./pkgs/development/haskell-modules/hoogle.nix.

I've never heard of this hoogleLocal derivation, and I've never seen anyone using it. I'd be fine with just getting rid of it for now. (Although I guess it might be sort of nice for someone that wants to easily use Hoogle.)

edit: Ah, looks like hoogleWithPackages introduced in this PR is effectively the same as hoogleLocal?

Comment on lines +90 to +94
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what situation is it critical that ensureAttrs is used here? (I'm mostly just curious...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When drv allArgs returns a function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I can see that, but what I'm trying to ask is what sort of call to callPackage would fail if ensureAttrs was not used here?

For instance, I don't think ensureAttrs is necessary for a normal call to callPackage that looks like:

callPackage
  ( { mkDerivation, lens, aeson }:
    mkDerivation {
      name = "my-haskell-package";
      ...
    }
  )
  {}

What would a call to callPackage look like where drv allArgs returns function? What would be the use of this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callPackage ./hoogle.nix { } and callPackage ./with-packages-wrapper.nix { } both need it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should have documented this feature, since it appears to differ from the top-level callPackage:

Here's an example showing what I mean:

with import <nixpkgs> {};

let
  myPkgExpression = { runCommand, lens }: prefix:
    runCommand "get-lens-version" {} ''
      echo ${prefix} lens version ${lens.version} >> $out
    '';

  myPkg = callPackage myPkg { lens = haskellPackages.lens; };

  myPkgWithArg = myPkg "my prefix";

  myPkgWithOverride = myPkg.override { lens = haskellPackages.lens_5_0_1; };

  myPkgWithArgWithOverride = myPkgWithArg.override { lens = haskellPackages.lens_5_0_1; };

  myPkgWithOverrideWithArg = myPkgWithOverride "my prefix";
in

myPkgWithArgWithOverride
# myPkgWithOverrideWithArg

myPkgExpression (and myPkg) define a package using callPackage similar to our new hoogle.nix and with-packages-wrapper.nix.

myPkgWithOverride and myPkgWithArgWithOverride then try to override the lens version, both before and after passing the actual "my prefix" argument.

With both of these, I get the following error:

error: infinite recursion encountered

       at /nix/store/g65b6lh3akdka0z9iji75yl07sb9n2s6-nixos-21.11.334247.573095944e7/nixos/lib/trivial.nix:364:19:

          363|   */
          364|   isFunction = f: builtins.isFunction f ||
             |                   ^
          365|     (f ? __functor && isFunction (f.__functor f));

I guess we should have explicitly documented this in haskellPackages.callPackage so that users see that haskellPackages.callPackage is a little more flexible than the top-level callPackage.

Copy link
Member Author

@sternenseemann sternenseemann Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather say that this is a potential bug in top level callPackage or a pitfall — in principle the behavior of top level callPackage is the same: cnovert a function to a functor set in order to be able to add the override attribute. Haven't tried debugging this particular case though.

Copy link
Member

@cdepillabout cdepillabout left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

Make ghcWithPackages.override { withLLVM = true; } (p: [ ... ]) work

I confirmed this with the following steps:

$ nix-shell -I nixpkgs=./. -p 'haskellPackages.ghcWithPackages.override { useLLVM = true; } (p: [ p.mtl p.conduit ])'
$ ... # create a file example.hs
$ ghc -v -fllvm example.hs

Looking at the output of ghc -v, I could see that LLVM was successfully being used.

@sternenseemann sternenseemann force-pushed the ghc-with-packages-overrideable branch from 10c9142 to 076451b Compare January 4, 2022 19:28
@sternenseemann
Copy link
Member Author

@cdepillabout added documentation as asked and cleaned up the hoogleLocal situation, thanks for spotting that!

@sternenseemann sternenseemann force-pushed the ghc-with-packages-overrideable branch from 076451b to 90a0d42 Compare January 5, 2022 08:54
This is achieved by passing the entire package set to the respective
wrappers and passing the select function as a second attribute. Together
with the new support for callPackage-ing functions this allows for
things like `ghcWithPackages.override { useLLVM = true; } (p: [ … ])`.

To make this possible for `ghcWithHoogle` as well, we need to make the
wrapper a bit more bespoke and inline the hoogle feature as well. The
hoogle wrapper, however, can remain separate and is exposed as
`hoogleWithPackages` additionally, as it can also serve standalone use.
`hoogleLocal` is kept for backwards compatibility (including the old,
suboptimal API), but will inform users about the better alternative via
a warning.
@sternenseemann sternenseemann force-pushed the ghc-with-packages-overrideable branch from 90a0d42 to ac72c1a Compare January 5, 2022 08:54
@ofborg ofborg bot added 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-darwin: 1 This PR causes 1 package to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. labels Jan 5, 2022
@ofborg ofborg bot added 10.rebuild-linux: 1 This PR causes 1 package to rebuild on Linux. and removed 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux. labels Jan 5, 2022
@cdepillabout
Copy link
Member

@sternenseemann I think this looks good. You want to merge this in?

@sternenseemann sternenseemann merged commit fb075fa into NixOS:haskell-updates Jan 6, 2022
@sternenseemann sternenseemann deleted the ghc-with-packages-overrideable branch January 6, 2022 11:21
@Mathnerd314
Copy link
Contributor

Overriding was already possible before this PR with the slightly different

(haskellPackages.ghcWithPackages (ps: with ps; [mtl])).override { withLLVM = true; }

Now this is broken. Sigh...

@sternenseemann please update https://haskell4nix.readthedocs.io/frequently-asked-questions.html#how-to-get-an-environment-with-ghc-and-llvm as well (on Github at https://github.com/NixOS/cabal2nix/tree/master/doc)

@maralorn
Copy link
Member

Oh, hugh. To be honest, the previous override seems much more plausible for me.

Did you simply not know that possibility, or are there arguments for the one over the other?

@sternenseemann
Copy link
Member Author

Overriding was already possible before this PR with the slightly different

Ah, very annoying, this did not occur to me at all, sorry! I'll amend the documentation and changelog as well. I also think we can add a thing that causes the old scheme to generate a nicer error message.

Not sure if I had done the same had I known this, but with the deed being done I do think it's an improvement, since it's overall a bit clearer and more consistent with the rest of nixpkgs and allows for overriding withPackages globally which wasn't possible before.

@sternenseemann

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: haskell General-purpose, statically typed, purely functional programming language 9.needs: port to stable A PR needs a backport to the stable release. 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-darwin: 1 This PR causes 1 package to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-linux: 1 This PR causes 1 package to rebuild on Linux.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants