-
Notifications
You must be signed in to change notification settings - Fork 74
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
Project Idea: Better haskell-specific tooling for working with nix #45
Conversation
Possible mentor: @ElvishJerricco |
@Ericson2314 and I have plenty of ideas for this. |
CC @kmicklas |
Doesn't |
@kmicklas I don't think
I'm sure there's more that's not off the top of my head. |
@Gabriel439 @intractable and @ixmatus may have thoughts on this... |
In theory you could directly translate a |
I'm still interested in what I layed out in http://lists.science.uu.nl/pipermail/nix-dev/2016-September/021765.html and haskell/cabal#3882 . The big difference between this and other strategies is that it gives most build planning responsibility back to cabal-install. Version solving is back in, hard-pinning versions in Nix is out. Derivations should be component-wise everywhere Cabal/cabal-install is, with per-module grandularity for both to eventially arrive simultaneously down the road. @kmicklas and I have resumed some preparatory work on Cabal, and hopefully there'd be a summer-sized piece we can break off from the rest. |
@Ericson2314: Wouldn't your proposal be subsumed by recursive Nix? cc: @taktoa The idea behind using Recursive Nix is that you replace the |
Also, with @Hadrian and dreams like haskell/cabal#4174, us Nix+Haskell people should be in better contact with @ndmitchell and @snowleopard. Extracting Nix derivations from Shake build plans would be a phenomenal way to better leverage our resources, but to the best of my knowledge is impossible with Shake's current design. CC @taktoa |
@Ericson2314: The point of recursive Nix is that you don't have to integrate with Shake at all. Once you provide the fake GHC wrapping Nix all Haskell tools that build on top of GHC automatically integrate with Nix. Instead of writing on Nix integration per package manager you write one Nix integration per compiler. |
@Gabriel439 that does work. But I've never really been excited about recursive Nix for, admittedly, basically aesthetic reasons. A single IFD step vs pervasive recursive nix is a lot less dynamism. More practically, it seems like quite a bit less work but changing Nix itself is, erm, politically quite difficult vs changing cabal, so it might not be. |
@Ericson2314: The reason I cc:ed @taktoa is that he tried exactly what you suggested for his summer internship at our company: using import-from-derivation to turn a |
Yeah @taktoa and I have talked a lot about it. Basically my plan differs from that summer in that I have lamer goal poasts: per-component builds for now, until the Cabal overhaul that everyone wants happens. I guess I'm more interested in cutting down nix-specific configuration and cabal-install duplication than better caching as my first priority. |
I want to point out a slight inaccuracy in what @Gabriel439 just said: doing incremental builds with recursive Nix will not automatically give us per-object file incrementalism (only per-component incrementalism), since |
AFICT, John's proposal doesn't have much to do with what @Gabriel439 and @taktoa are describing. John's talking about porting the package-level (component-level?) build plan of John's plan of bringing back the solver in Nix does not resonate with me. I'm personally much more a fan of snapshot curation than solving. It's particularly relevant in Nix since we can provide binary caches for snapshots. Requiring each project to have its own freeze file means that each project needs its own binary cache (granted, most companies do this themselves anyway). As for incremental Nix, I don't think we need to go for full generality just to get something worthwhile for Haskell. At the risk of suggesting something that more knowledgeable people have already discussed: Why can't we just add a command to Cabal that subs One concern I have for recursive Nix: Showstopper for recursive Nix for me: Doing it properly means having to properly interpret GHC's entire command line interface in order to intercept it. This is pretty hard, and likely to work differently between GHC versions. After having countless issues with the cc-wrapper in nixpkgs, I tend to prefer avoiding sophisticated wrappers. Something using IFD would be far more attractive to me (and I'm not convinced this isn't the best option anyway, even ignoring this particular issue). @Gabriel439 FYI, Regardless. I really don't think the focus this year should be on radical reimaginings of how Haskell works at the fundamental level in Nix, unless we can get incremental Nix+Haskell with relative ease. Otherwise, I think the focus absolutely needs to be on things that prevent people from adopting Nix, not on things that already-nix-users would enjoy. Roughly these fall into these categories:
Getting people in the door should be priority #1. With the right knowhow, Nix is already powerful enough; so we need to focus on making that power accessible to new people. |
@ElvishJerricco: Regarding documentation on using Nix for Haskell development, have you seen: https://github.com/Gabriel439/haskell-nix Also, to clarify: I'm not recommending that the Summer of Haskell project should be to implement or use recursive Nix (quite the opposite) I also agree that I prefer the snapshot model (i.e. how both Stackage and |
Interestingly, @Ericson2314 seems to be interested in the only part of this project that is made easier with Recursive Nix, so I suspect this will come down to just overhauling Cabal. Here are some things that people could work on that seem independent of the IFD / Recursive Nix divide:
|
Oh, somehow I didn't notice that there was actually a proposal to read here. I wrote all that without having read anything other than these comments. I'll read the proposal now and comment again with my feelings on it. |
My responses to the contents of this proposal:
|
Yes, and a few other like it. These are the sorts of resources that need to be put somewhere that a beginner is likely to actually find, specifically the nixpkgs manual. @Gabriel439 @Ericson2314 @taktoa Can we all agree that the discussion @Ericson2314 and @taktoa are having is about an issue that is out of scope for the SoC? If so, it should probably move to a different thread. |
@ElvishJerricco |
I didn't notice this comment before, but this is basically what I tried to implement last summer. There are a bunch of problems with this approach:
The wrapper script we write that pretends to be GHC can be written in any language, including Haskell, so we could just reuse GHC's command line parser. The algorithm here is basically:
At the end of the day, Recursive Nix means that we can inject ourselves into the build process in a way that is completely agnostic of the build system, and only concerns itself with the semantics of the compiler. IFD-style approaches are highly coupled to the build system. In Haskell we pretty much only have one build system, but for other languages there are many, so Recursive Nix really is just more scalable solution. |
I agree with @taktoa 's arguments for recursive Nix. Another reason I am somewhat against IFD as a solution to these problems is that it entrenches the privilege of Nix-the-configuration-language to be the one sole way to control Nix-the-generic-computation-memoization-system. Recursive Nix provides a much more coherent layering story where any tool can hook into the caching system. Someday theoretically even the Nix language evaluator could be implemented this way so the evaluation of nixpkgs could be cached. But issues with the design of Nix are probably outside the scope of Summer of Haskell... |
I don't see how this is true. An alternate evaluation language would be just as capable of this as Nix. Anyway, I really don't think we should continue the discussion about recursive Nix here, if we don't think we're going to be proposing it as SoC project. |
This thread quickly spiralled out of control whilst I was away over the weekend! It's great that there is lots Recursive nix is definitely off the table and I deliberately left incremental rebuilding from this proposal It seems that @Ericson2314 has previously considered this question in a lot of detail but I don't understand the concrete proposal from the original email thread. There is more detail in the ticket however it hasn't been updated since 2016 so I'm unsure what the status of the proposal is. It really needs a single cohesive summary so that people can understand it better. I think @ElvishJerricco summed up the situation well at the bottom of his earlier comment. Thanks to @taktoa for his thoughtful comments on the proposal. He is right that What is important now is that we can specify a contained, well-motivated proposal rather than bigger design philosophy questions (which can gladly continue in other forums). Can anyone suggest a suitably sized well-specified chunk that they think would be appropriate? Will's earlier comment is a good start I think. |
Here's one concrete proposal: Cabal2nix for cabal.project filesI want to be able to use
And produce the following Nix file:
This is sort of incomplete (we need more in the Bonus points for creating a
|
content/ideas/cabal-nix-workflow.md
Outdated
environment. It is not usual for the test dependency tree to quite a bit larger than the | ||
build dependency tree. Ideally, when a user runs "cabal build", cabal should enter | ||
a nix shell with the appropriate build dependencies for building whichever component | ||
it wants to build and no more. Similarly, "cabal test" should load enter an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"should load enter an" doesn't look quite right.
I very much second @ElvishJerricco's proposal. I have in fact been discussing an idea like this on and off in the past few months with @hvr and @bgamari. It is the biggest missing bit of infra for me. I'm quite often not really happy with the package sets that we have in nixpkgs and would more generally welcome some more tooling to easily create them "from scratch" or from existing ones. It seems very natural to just lean on cabal-install's solver to figure out everything we need to generate a nix expression that will faithfully reproduce the versions and what not that cabal-install would use if it were to build the packages itself. Handling dead-simple scenarios should not require a lot of work, especially given that we have things like cabal-plan to help us. The devil will probably be in the details (like being able to interpret everything we can possibly see in a cabal.project or .cabal file in Nix terms). It would be nice of course to have more user-friendly Nix functions or CLI tools to generate our own package sets for all sorts of situations (that is, more user-friendly than the ones we have in nixpkgs at the moment), but I'm unfortunately not able to provide a good specification for what I would like to have, so in the meantime @ElvishJerricco's proposal would already go a long way towards making my life easier :) Regarding cabal --nix and stack --nix: I have used both in the past too, they work OK but it seems to me like there isn't much more to be done except polish things up a little bit and write more documentation and examples so that people who're just getting started with Nix can easily build with their projects with This would also allow us to build more things on top of it: generate a |
Thanks @ElvishJerricco, I think that's definitely a good place where a student could get started. There is plenty of food for thought in this thread now but it isn't our responsibility to completely write a student's proposal for them! I'm also curious about what additional documentation you think is necessary for the haskell nix ecosystem? I have been trying to think of things that need writing about but nothing seems to jump out at me. Gabriel's |
I think @bgamari's work is a bit stronger than I was hoping for. It looks like it actually looks at your cabal build plan and produces an entire package set from that? @alpmestan is this something more like what you would have hoped for? I think it's valuable to have this as an option, but I think it's important that our tools are built around the default of using @mpickering Those github guides are indeed great, but they're in very much the wrong place. I usually have users come to me asking for help saying they've looked at my documentation on reflex-platform, sometimes the nixpkgs manual, and rarely anything else. Preferably, everything that is general to nixpkgs needs to be in the manual. And preferably, more of the Additionally, you'll find almost no documentation on the functions in EDIT: Spelling |
Yes, I'm absolutely fine with defaulting to what nixpkgs comes with, really all I'm suggesting is to make it easy to use other package sets, which naturally prompts the question of how we can make it easy/trivial to create other ones. We already have overriding/overlay mechanisms in nixpkgs to tweak existing ones, but there is no simple way to "mass-import" a bunch of specific package versions in an attr set and call that a package set, with the same capabilities as If you have packages I haven't looked in great detail at Ben's code but I don't think it handles that yet. It would also be nice to be able to retrieve and apply the flags specified in cabal.project files (or more generally the flags that Anyway, sorry for hijacking the discussion with my specific use case. I do think the "mass-import" thing would be nice, with the possible bonus of handling flags and all sorts of reasonable cabal.project options and what not faithfully. This looks like a rather well-defined project, Ben's patches are a good starting point and I don't think a summer is either way too long or way too short to build the "mass import" bit in a way that supports multiple versions of a same package (or even same version but configured differently, e.g with or without some flag?) and ideally even picks a suitable compiler version when there are constraints on it (and defaults to the latest major release or something), and then "decorate" the list of packages so that it behaves like Not sure that kind of project is an easy sell to the broader haskell community though. |
So generic-builder.nix will always be playing catch-up with Cabal, and this is really bad for new users. It's not that the missing features are necessarily crucial, but the fact that there is an impedence mismatch that makes it inhospitable. This is why I want to move towards leveraging cabal and cabal-install more: less nix code means fewer pitfalls relative to Cabal. As far as package sets go, we can easily replicate them with cabal constraints in project files. Nixpkgs can contain big fat ones of those which it will cache, and projects can copy it into their cabal.project.local. This is great because it's a completely nix-agnostic solution. |
@alpmestan That doesn't sound like a thing cabal.project is supposed to be used for... Anyway, we do have |
Hm? I'm just describing the simple case with
Right, this is what I alluded to in a comment above. What we're missing is some infra to populate package sets using this by directly getting the versions and what not from |
@Ericson2314 I really want to understand what your vision for your projects are but I'm having a hard time. Please can you clarify with lots of examples so that I can understand how you are planning to proceed. You say that "this is why I want to move towards leveraging cabal and cabal-install more" but isn't that what @alpmestan is also suggesting? He is suggesting taking the output from cabal, whatever plan it decides, to set up the environment. This is already using Cabal more as currently what Cabal thinks the plan should be isn't really taken into account, the information is just parsed from the cabal file. This seems to also be exactly in line with the first paragraph on haskell/cabal#3882. Perhaps it would be useful to everyone if you could briefly describe what you imagine the precise responsibilities of cabal to be and the precise responsibilities of nix. I think that would go a long way to clarifying the situation. |
@mpickering yeah sorry, was responding to @ElvishJerricco; edited to make clear. @alpmestan and I are advocating for the same sort of thing, as far as I can tell. I want cabal to solve for all versions and everything, and come up with a completely static dependency graph which Nix then builds. Ideally that graph would eventually be per-module granularity, but I think offloading the planning to Cabal is more important than making the graph fine-grained. I need to do more investigating of cabal-install's source, but I recall it does already strive to be as static as possible. So exporting that into a course pkg- and component-granular (need to be conservative with custom setups) build graph for Nix shouldn't be too hard. |
@alpmestan Ah I see. Regardless, I do not think
I get:
It wants to use one solved plan for the entire project, and I think this is sane. @Ericson2314, requiring users to copy a cabal config out of nixpkgs, and somehow keep that in sync as nixpkgs gets updated, in order to keep the cache working, is exactly the sort of thing that causes astonishment for newcomers. And I personally would be extremely frustrated to have such a workflow by default. I agree that using a cabal solved plan should be possible, but the default should definitely be as it is today: A curated snapshot that requires zero hassle, and minimal astonishment to get to work with. Point being, a |
@ElvishJerricco Don't take my "copying" method as something permanent. People already want a way to import constraints for LTSes, so I'm sure something could be put together. They way curated packages work today is atrocious. We rely on each So, no problem if you want "use the cached package set" to be the default, but we really ought to accomplish it in the way I describe. We could wrap cabal (or have the IFD derivation) pass the nixpkgs default constraints by default, for example. Really, my priority here is not fighting new-build over joining the version-solving vs curated package sets brawl, here. (Though yes, full disclosure for everyone else, I do prefer the former as I've told you in person.) |
The |
@gbaz Yeah plan.json is a good start. But it's just sort of an ad-hoc sample of different properties of the install plan, more as a demo and for debugging than anything else. I'm not sure whether its better to continue dumping more stuff in it, or start over. For the record, there was a similar issue where the Rust Cargo people were wondering whether the "lockfile" (like new-build freeze file) was sufficient, but no it wasn't Cargo never attempts to do everything from the lockfile alone. What we need is cabal-install to dump something which it can then ingest as its sole input and do everything else with, to prove that the information therein is indeed sufficient. At this point, I'm pretty convinced that such a proof is the only way to keep the language package managers honest :). |
My understanding is that plan.json doesn't contain everything, but it contains "everything you need to get everything". I.e. it can point you to what cabal files you want as well, and the union of the cabal files and the plan.json information is sufficient? Or is there something I'm missing... |
@Ericson2314 IMO (I may be biased, because I'm in part to blame for the way |
Ok I'm just out of date I think. Glad to be wrong :). |
So here's a brief attempt to form @Ericson2314's thoughts into a more concrete proposal, potentially for the SoC: Building custom Nix package sets from
|
@ElvishJerricco maybe that's a good first step, but I want to stop using |
@Ericson2314 Could you briefly summarize how/why a SoC student would work on getting rid of |
|
@Ericson2314: I don't follow. |
(@Ericson2314 maybe off-topic, but is there anything interesting mentioned around haskell/cabal#4646 (comment) that could be relevant to this discussion?) |
@Gabriel439 So concretely I don't think we should be But more important to me in the prinicple of deduplicating stuff. I'll need to get back in the |
@jaspervdj What is needed in order to merge this idea? |
@mpickering Nothing from your side -- I got a bit behind on the voluminous discussion on this ticket. I'll review it this week to make sure it's somewhat agreeable to all parties involved and then get it merged. |
Reformatted/tweaked and merged in #49 |
Link to rendered proposal.
https://github.com/mpickering/summer-of-haskell/blob/034bd1b9759e17d2d57ccdf8d0e9bf1c5663ed13/content/ideas/cabal-nix-workflow.md