-
Notifications
You must be signed in to change notification settings - Fork 698
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
Interface for system package manager to execute build plan #3882
Comments
/cc @ttuegel |
Related: #3651. |
So it's my opinion that (to borrow the git terminology) |
That sounds fine, but it does mean we have to commit to a more stable and documented
Are you sure you want to add a new single component manifest format, as opposed to
I don't know what you mean by this. Could you maybe write some concrete JSON pseudocode describing what a sub plan looks like?
Did you mean
new-build caching works in a very specific way: for any specific unit identifier we depend on, we look in I didn't read the section on local dev with Nix, I know very little about how it works. |
@Ericson2314 are you interested in contributing and maintaining the necessary patches to cabal-install to make this work? I think it would be much appreciated by the Nix community. |
[On subway so limited Internet.] I'd hope since this isn't Nix-specific I wouldn't be solely on the hook for maintenance :), but I'm certainly down to implement. |
Despite appearances, #3651 is actually orthogonal to this issue. What is proposed here is really an alternative to I don't think this proposal offers any features beyond what |
I want to single-out one statement from the mail to nix-dev:
The |
Well, if there is a helper executable to call GHC etc on behalf of the system package (e.g. stock
Because all the configuration should be done beforehand by cabal-install, the CLI for this should be very simple and need not look nice so as to not sqat on valuable CLI real-estate should it need to be deprecated.
In the mailing list, I erred on the side referring to cabal-install, as I am not sure quite what the division of labor is for new-build. Here, I went on a limb and proposed using ./Setup, hoping Cabal is enough. Sorry for the inconsistency + confusion.
That is icing on the cake / more #3651's territory, so feel free to ignore it for now :).
Well, to get the easy concerns out of the way, we would have one new-style Now the complex bit. Well, what, if anything in Extrapolating from Nix, I assume building needs more than the [One final hiccup is I'd like not to have all non-haskell deps build and exposed at |
@ttuegel Hmm? it was my understanding that we |
[edit pipeline sketch is now at the top of this thread] |
CC @peti as this is more active than the nix-dev thread. |
Come to think of it, this may also benefit getting rid of ghc-cabal in Hadrian (snowleopard/hadrian#18). The analogy is Nix : Nixpkgs : cabal2nix :: Shake : Hadrian : ghc-cabal. |
This thread is sprawling so I'm going to respond comment by comment. But maybe there is some big picture comments that need to be made.
At the very least, the tools should realize that plan.json defines a number of install items which each can be built and installed individually. After all, you want a one to one correspondence between install item and Nix derivation. (I don't call these packages because they are not necessarily packages; e.g., with per-component builds you'll get an install item per component.) And you also need to know the dependencies for Nix derivations. So I'm very doubtful you want to black box this.
The only "configuration" cabal-install does today is compute the set of flags to pass to
So, I am still not sure if this is what you actually want, but we'll have to do some work in this case. Maybe you just don't ever want improvement to take place for Nix-style, in which case you just don't need the store at all.
If you are never building any inplace packages, as would be the case for non edit-recompile, then there is NOTHING in dist-newstyle that actually gets used. Certainly cabal new-build will cache the result of dependency solving so that it runs faster, but you could safely just always blow away dist-newstyle before computing one of these plans.
But obviously you need the source for the Cabal package, to actually build? I mean, you also need to have the dependencies in a visible package database for the build. But if you're calling Setup directly you can just pass in all the package databases of each of the dependencies that were managed by Nix and that would be fine. I wonder if there is some architectural description that is missing here but would help guide the discussion
I'm still confused. Aren't you going to make a derivation per install item, which depend on each other?
I think that's true? But it's still hard for me to understand what gave you the idea that you need a plan for each transitive dependency. |
OK, so maybe we can do something to make Nix's job easier here. The way that pkg-config deps are handled is Cabal just calls pkg-config to figure out what information is necessary. In fact, this call doesn't happen until we actually are configuring with
But if you're calling the Setup script directly, you can just download the tarball as you want it, unpack it, and then you're off to the races. But note that you may need to build the Custom setup script.
See my comments above. Can't you just build the derivations as you traverse the build plan.
The point is that you're not going to use new-build to actually build, right? So you're just going to call the Setup script directly, so you don't have to worry about any caching business. OVERALL: So, maybe it would be helpful if there was some architecture document describing how all the pieces of Cabal/cabal-install fit together? |
Thanks, these comments help a lot.
For reference, https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/generic-builder.nix is how we currently invoke |
Ok good, that shrinks the difference between how things already work and how I want them to work. This project basically becomes shrinking that file I linked.
Ok I'm convinced. I'll reduce my claim to that the flags for each ./Setup command can be a plan list—we shouldn't need to know why they are passed. |
What is "improvement"? Finding something already cached? I'm fundamentally relying the nix derivations to be the same whenever cabal-install would use its cache on its own. So maybe you're right in that we don't rely on the new caching, just the ability to write down the plan up front. |
I mean what must be preserved in between the creation of the plan and it's execution—and remember cabal-install won't be present to execute the plan. So it's sounds like all we need to extract and preserve from that directory after cabal-install is run is plan.json? |
Oh yes, duh. I probably meant in addition to that.
I was trying to get at what I just commented above. Without cabal-install computing the grand plan on the fly, we need to get those flags for ./Cabal into the nix derivation. |
I was thinking if we needed to compute the flags on the fly from the plan for transitive deps. But if the plan already contains all the flags scratch this. All we need is the JSON object for the current install item and the flags it contains. |
Yeah, so as far as invoking |
Oh great! Perhaps cabal-install could just copy any relevant native library deps to plan.json, so the new cabal2nix just needs to look at |
That's fine--great if the plan.json can contain everything we need (including hashes) to do this download. I assume
Heh, that's the last hitch. I'd love the plan to build custom setups as a separate item. Also for cross compiling (including GHCJS) we use a native compiler to build Setup scripts, so it would be cool if cabal-install could work that way too. |
As long as |
Yes! All I knew going in to this is a) cabal-install is the executable b) Cabal is the library that cabal-install and Also, while I need to stop thinking about this right now, I'll eventually go back and edit my summary comment to reflect what's been cleared up. |
I have been trying to understand this proposal from a Nix perspective for a while now, but the purpose of these suggestions continues to elude me. In particular, I don't understand what problem this proposal is supposed to solve. Can someone please give me concrete example of a use-case that doesn't work in Nix today but that would work if this proposal were to be implemented? |
The primary purpose is to make our Haskell infrastructure smaller and simpler by leveraging cabal-install, not to add more features. The ghcjs problem I mentioned in the mailing list thread has been fixed: NixOS/cabal2nix#230 but with these changes such problems would never occur because no nix-specific code (cabal2nix, nixpkgs, or otherwise) would need to evaluate cabal files. I've talked about a nicer workflow for local development, but haven't been able to articulate that clearly, and as I say above it icing on the cake, so let's just ignore that extra work + extra benefits for the time being. |
Yep I agree.
Yeah. So the way that cabal new-build works is that first computes a plan from first principles; i.e., it doesn't look at the store at all. Once it has the plan and computed all the hashes, only THEN does it "improve" the plan, replacing the packages it planned to do with the ones that are actually stored.
Yeah. Setup script doesn't use any of the cabal-install infrastructure; it creates dist directories on its own.
It contains a package database.
The plan already contains flags.
I guess we could record the build-tools? Put that in the summary. (see more below)
It probably has enough info? (Maybe it's missing which Hackage revision was used?) In any case if it doesn't we should add it.
Yep, that's something I want too. Not implement yet, alas.
Hmm, actually, that is not going to work, because if you build it inplace it will get inplace package IDs, which is not what you want. Maybe make a fake package which build-depends on the stuff you actually want to build? (I wonder if cabal new-configure pkg1 pkg2 pkg3 works...)
Yes please do. Actually, put it at the top of the ticket, please! |
@Ericson2314 I would seriously consider opening up a https://github.com/ghc-proposals/ghc-proposals for your summary. It will make following the convo easier, as you can just update the proposal doc as you learn more. |
@ezyang Cool, it sounds like we are on the same page now.
Ah, OK. I hope improving just means skipping/removing install items that are built, not modifying any of the others?
Oh well, makes sense.
I don't think the fake package would if the root set includes executable, however. Even putting them as a tool dependency would fail when cross compiling as those are (or ought to be) built natively. However I do wonder if a better strategy is to build anything that transitively depends only on Hackage sources in the deps, and anything else in the local cache. This is only slightly different than currently as external deps that depend on local deps are already built in the local cache. A local package would then probably be redefined as just anything not from Hackage.
Ok put it at the top for now, but I'm happy to write a formal proposal too when I have the time. I want to do this with Cargo too eventually, so I imagine I'd get some pretty sweet prose reuse :). |
No modification occurs.
Good. Note that you probably don't want to call individually, because then the dep solver has latitude to pick different deps for each package in each case. Probably not what you want.
I don't understand. If a Hackage source depends on local source code (not on Hackage) of course it can't be installed globally. |
Oh yeah, I was forgetting that while I can use the same project file that is not enough to guarantee same constraint resolution unless I lock down every package.
Yeah that part remains the same. Basically I am saying make |
Yes, that seems like a reasonable design. @dcoutts what did you think |
To which components does |
Mu. The question is equivalent to saying what components does |
Bump. @dcoutts do those semantics for |
Now a few year's later, there's https://github.com/input-output-hk/haskell.nix which gets the division of labor just about right. (Any further improvements would involve big changes to Cabal itself; stuff I won't propose just yet :).) |
Original Post
I wrote a fairly long email to the nix-dev list (http://lists.science.uu.nl/pipermail/nix-dev/2016-September/021765.html) proposing that
cabal2nix
work fromcabal-install
's build plans instead of the package cabal files themsevles. This would obviated needing to teach it to resolve configuring options etc, basically replicating Cabal. [The idea is of cabal-install resolving the plan and the system package manager executing the plan generalizes for any system package manager, not just Nix, hence not singling Nix out in the issue title.]Reading the cabal-install section of the componentized Cabal proposal leads me to further propose that
plan.json
(or whatever should be the interface between the system package manager and cabal-install) contain exactly the component dependency graph proposed in the RFC. This granularity would be nice for Nix for the same reason it is nice for cabal and stack---I personally will contest that playing around with some packages and then having to rebuild them to enable tests is quite annoying.A final extension to that would be to extend Cabal itself to also work from these a single-component manifests. The default Setup binary would gain the ability to work from either a manifest--corresponding to a single component, or a bunch of manifests--corresponding to that component and its dependency closure. [I say either because I am not sure whether the new-* work affect Cabal or just cabal-install. If Cabal too, I assume the closure is needed, if just Cabal then the single component's manifest is probably fine.]
There are two advantages of this final bit. The first is that we currently only use Cabal, not cabal-install, in Nix Haskell packages, and this would allow us to continue doing that. That said, I'm not sure what the advantages of this current approach so this may not be good motivation. The second is were we also wanted to use stack to generate build plans, the component dependency dag is probably a good format for both to support (I speculate given that the componentization proposal was originally @snoyberg's idea).
stack --nix
already exists but for reasons given in my mailing list post, I think the mechanism I'm describing would work strictly better.Anyways, after writing the proposal for the Nix list, I thought it would be good to get the attention and opinion of upstream.
Current Plan for Nix
For non-local dev (packaging executables for nixpkgs), here is a sketch of the entire process:
cabal.project
extra-packages:
for the executables, since they come from hackagecompiler:
to specify the compiler so we don't it built at config time.cabal new-configure
without any network access and limited FS access only to cabal-install's runtime deps + downloaded index.cabal/config
already handles this? I assume we can put the config elsewhere with a CLI flag?plan.json
contains "install items" each with:./Setup
with all flags./Setup configure
is still responsible for checking whether those libraries are present, butcabal configure
can anticipate when they will be looked-for.)plan.json
into a package set where each "install item" becomes a derivation. Either this comparatively simple task is the new job of cabal2nix, or this is so simple we can just usebuiltins.fromJSON
and write in Nix../Setup
commands specified in the proper phases. Hopefully we passcabal new-configure
enough so that the./Setup
flags do not need to be modified.Work to be done
The text was updated successfully, but these errors were encountered: