Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

haskellPackages.shellFor: Fix ghc calls #46453

Merged
merged 3 commits into from Oct 2, 2018

Conversation

infinisil
Copy link
Member

Motivation for this change

This cost me a couple hours to figure out. The original error was

Got error while processing diagnostics: <command line>: cannot satisfy -package-id hnix-0.5.2-5hMz8sQY4ky2OCdjsvbD9J

from ghc-mod via HIE. After a very long time of debugging, I finally figured out that the reason was that shellFor doesn't run any shellHook that sets up the correct NIX_GHC* env vars to have it find stuff. This PR just does a dirty fast fix by copying part of the logic in generic-builder.nix, please don't merge it like this.

Ping @peti @ryantm @basvandijk @domenkozar (Ping the people I annoyed for hours in #haskell-ide-engine because of this: @alanz @DanielG)

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Fits CONTRIBUTING.md.

@teto
Copy link
Member

teto commented Sep 10, 2018

I think I had a similar problem domenkozar/hie-nix#27. even though I didn't use shellFor

@basvandijk
Copy link
Member

basvandijk commented Sep 10, 2018

Great work!

Now I wonder, can't we use shellFor to implement env in the generic-builder.nix?

Not that that's a prerequisite for merging this PR. I think we should merge this now and see how to DRY it later.

@infinisil
Copy link
Member Author

@basvandijk Hmm, I usually don't like introducing bad code into nixpkgs. I'll see if I can refactor it in the next couple days. If I can't, then we should probably merge this, as it clearly fixes a bug and potentially lots of frustration. Also this might need backporting

Also pinging @ElvishJerricco who introduced the function originally in #36393

@ElvishJerricco
Copy link
Contributor

This is not the only place this logic is duplicated in the haskell infra, IIRC. We really need a generic solution to this...

@infinisil infinisil changed the title [HACK] haskellPackages.shellFor: Fix ghc calls haskellPackages.shellFor: Fix ghc calls Sep 17, 2018
@infinisil
Copy link
Member Author

@basvandijk @peti @ElvishJerricco Please take another look, I cleaned up most of the duplication

Copy link
Contributor

@ElvishJerricco ElvishJerricco left a comment

Choose a reason for hiding this comment

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

I like the idea of defining haskellDrv.env in terms of shellFor!

haskellDrv = callPackageWithScope defaultScope drv args;
in haskellDrv // {
env = self.shellFor { packages = p: [ haskellDrv ]; };
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will break if you try to use (overrideCabal haskellDrv ...).env. It's probably easiest to either declare this in passthru in generic-builder.nix, or to use overrideCabal here to add it to passthru. I'd prefer the former.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem with the former is that shellFor doesn't work with a "raw" derivation, because it depends on .overrideCabal being available, which is only added with callPackage.

I'll test if this really breaks it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah. Then yea adding with passthru and overrideCabal is important. As is, any use of overrideCabal will wipe out this env.

Copy link
Contributor

Choose a reason for hiding this comment

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

@infinisil Actually, I dunno if there's a way to fix this at all. We always want to refer to the final version of the derivation. But overrideCabal doesn't give you that. So even if we manage to preserve env via overrideCabal, it'll be the wrong env as soon as anyone does overrideCabal again; i.e. if they add a dependency, it won't be added to env.

Copy link
Contributor

Choose a reason for hiding this comment

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

So maybe we need to invert the control here: put the source of truth in generic-builder and define shellFor in terms of that.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, how about putting the extractBuildInputs thing as a generic-builder passthru, define it in terms of that. I think that's the only thing that depends on overrideCabal.

Copy link
Contributor

Choose a reason for hiding this comment

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

@infinisil Yep, sounds good. Eliminating overrideCabal entirely from the equation for extracting build inputs sounds like a really good thing.

# If `packages = [ a b ]` and `a` depends on `b`, don't build `b`, such
# that `a` will take the `b` dependency from the cabal.project file.
# This allows changing `b` while in the shell and have `a` use the
# changes directly.
Copy link
Contributor

Choose a reason for hiding this comment

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

cabal new-build is happy to ignore any installed b actually. The real reason for this is to avoid building b with Nix at all, so that entering the nix shell doesn't require rebuilding b every time it changes when you're just going to ignore that version of b.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh good point, will adjust that message

mkDrvArgs = builtins.removeAttrs args ["packages" "withHoogle"];
in pkgs.stdenv.mkDerivation (mkDrvArgs // {
name = "ghc-shell-for-packages";
nativeBuildInputs = [(withPackages (_: haskellInputs))] ++ mkDrvArgs.nativeBuildInputs or [];
name = "interactive-${pkgs.lib.concatMapStringsSep "-" (p: p.name) selected}-environment";
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm this naming could be a bit much. I think it'll be common for selected to have quite a few packages, e.g. 10+

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I think maybe just "interactive-${name}-environment" if it's a single package and "interactive-multi-package-environment" or so if it's more than one would be better.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer just having a generic name, but allowing mkDrvArgs to override the name however the user likes; but it doesn't matter very much

${if ghc.isHaLVM or false
then ''export NIX_${ghcCommandCaps}_LIBDIR="${ghcEnv}/lib/HaLVM-${ghc.version}"''
else ''export NIX_${ghcCommandCaps}_LIBDIR="${ghcEnv}/lib/${ghcCommand}-${ghc.version}"''}
${mkDrvArgs.shellHook or ""}
Copy link
Contributor

Choose a reason for hiding this comment

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

I like adding these environment variables, but I'm pretty sure it needn't be done in a shellHook. Maybe I'm being picky, but I think it seems nicer to just set them as mkDerivation arguments to me :P

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, that's a good point, I just copied it from before, but that sounds much better, will change.

// optionalAttrs (hardeningDisable != []) { inherit hardeningDisable; }
// optionalAttrs (stdenv.buildPlatform.libc == "glibc"){ LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; }
)
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Recommended to hide whitespace changes (Click on Diff settings above).

I don't see any other way than this to add .env to passthru. Because it itself depends on the thing.

_getBuildInputs = extractBuildInputs p.compiler args;
};
}))._getBuildInputs;
getBuildInputs = p: p.getBuildInputs;
Copy link
Member Author

Choose a reason for hiding this comment

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

This change very slightly changes the results of this function, namely that setupHaskellDepends is not in haskellBuildInputs anymore. It is in the derivations nativeBuildInputs though, and therefore included in nix-shells.


assert allPkgconfigDepends != [] -> pkgconfig != null;

stdenv.mkDerivation ({
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any way to avoid re-indenting everything? Makes it harder to review and kills git blame.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can just do fix (drv: stdenv.mkDerivation ({ and add a paren at the end?

Copy link
Member Author

Choose a reason for hiding this comment

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

You could add -w to git diff or git blame :)

I guess the github blame's won't work with this though. I could of course just not indent it, but then it's kinda ugly

Copy link
Member Author

Choose a reason for hiding this comment

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

Or fix, yeah that sounds better

in
drv // {
env = buildHaskellPackages.shellFor {
packages = p: [ drv ];
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a duplicate of line 432? We should only have the passthru one.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh yeah good point, will remove

"NIX_${ghcCommandCaps}_DOCDIR" = "${ghcEnv}/share/doc/ghc/html";
"NIX_${ghcCommandCaps}_LIBDIR" = if ghc.isHaLVM or false
then ''export NIX_${ghcCommandCaps}_LIBDIR="${ghcEnv}/lib/HaLVM-${ghc.version}"''
else ''export NIX_${ghcCommandCaps}_LIBDIR="${ghcEnv}/lib/${ghcCommand}-${ghc.version}"'';
Copy link
Contributor

Choose a reason for hiding this comment

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

export?

};

env = buildHaskellPackages.shellFor {
packages = p: [ drv ];
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think buildHaskellPackages is right.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm right, I guess it doesn't matter much though, because the p is ignored anyways, so no dependencies come from that set anyways. It was the easiest way to get access to shellFor.

Copy link
Contributor

Choose a reason for hiding this comment

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

@infinisil Does it control where GHC comes from? This will get the GHC for targeting the build platform.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah you're right, will have to do something about this then

@infinisil
Copy link
Member Author

Cleaned up all the commits, very tidy now

else ''export NIX_${ghcCommandCaps}_LIBDIR="${ghcEnv}/lib/${ghcCommand}-${ghc.version}"''}
${shellHook}
'';
env = buildHaskellPackages.shellFor {
Copy link
Contributor

Choose a reason for hiding this comment

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

@infinisil In the case of cross compilation, this will give you a shell with a native GHC rather than a cross compiling GHC, won't it?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it'd be better to have a haskellLib function for shellFor that takes GHC and a list of packages as arguments. Then haskellPackages.shellFor can be a convenience for plugging in GHC automatically and letting packages be a function for convenient access to the package set as an argument.

@@ -46,6 +46,7 @@ let
inherit buildHaskellPackages;
inherit (self) ghc;
inherit (buildHaskellPackages) jailbreak-cabal;
inherit (extensible-self) shellFor;
Copy link
Member Author

Choose a reason for hiding this comment

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

Passing it like this now

@infinisil
Copy link
Member Author

infinisil commented Sep 17, 2018

Rebased, fixed conflicts, and now using self.shellFor instead of extensible-self, works better.

@ElvishJerricco
Copy link
Contributor

@peti If I understand correctly, ghcWithPackages is unaffected by this PR. env always was built on top of that. Now env is built on shellFor, which is still built on ghcWithPackages.

@infinisil
Copy link
Member Author

I have tested this myself successfully on my nixbot consisting of two subprojects, and just running nix-shell -E 'with import ~/src/nixpkgs {}; haskellPackages.xmonad.env.overrideAttrs (old: { buildInputs = old.buildInputs or [] ++ [ haskellPackages.cabal-install ]; })' and running cabal build in xmonad's master revision.

Unrelated: I think cabal-install should be included as a buildInput/nativeBuildInput in all .env's, it's annoying to always have to override it.

@peti peti force-pushed the haskell-updates branch 3 times, most recently from c77ce53 to a4badb2 Compare October 2, 2018 19:09
@infinisil
Copy link
Member Author

@peti Rebased to fix conflicts, didn't make any changes. Would like to get this merged.

@ElvishJerricco
Copy link
Contributor

Is there a chance we could backport this to 18.09? Who would be able to make that decision?

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

Successfully merging this pull request may close these issues.

None yet

9 participants