-
Notifications
You must be signed in to change notification settings - Fork 696
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
RFC: cabal init
by default pins the ghc version via with-compiler
#5661
Comments
FWIW, any pinning you'd want would go in My two cents: This and freeze files by default are an idea I'd appreciate for products, but not for infrastructure. i.e. Any libraries or build tools that someone wants to push to Hackage should be as relaxed and unpinned as reasonably possible. But when someone starts an end-use product, and not some library or infrastructure to be used by other projects, they invariably want a pinned down environment. The problem is that drawing the line between these two use cases is hard, and it's hard to know which should be catered to. |
TIL, SGTM :)
Here's my take on it: people who are developing Haskell libraries and infrastructure are (almost) by definition more familiar with the ecosystem and the tools, and they know they don't want a pinned version because they likely test with numerous versions of GHC anyways. Conversely, those who are building a product just "want things to work", and may not be as familiar with the ecosystem and how changing a global binary can cause builds to fail in projects. This latter group includes all beginners, hobbyist users of Haskell, and folks who build products using Haskell; I would wager quite a bit that this group is orders of magnitude larger than the former (or would be if Haskell became mainstream) :) I guess my opinion can be summarized as: "cater to the beginner, make the advanced user do a little extra work". If the beginner needs to know about specific configuration options just to make their toy program build then I would say we're doing something wrong :) |
If cabal is going to get training wheels, there should be a way for advanced users to permanently remove those training wheels. I'm even fine with training wheels being the default, but they need to be optional. |
Agreed, this is probably something that could go in the user's global cabal configuration file. I'm sure one of the cabal developers would have a recommendation for how to accomplish this nicely. |
IMO writing absolute ghc path to Also
which "pin-points" the GHC close enough.
I also don't want And finally, how many beginners or casual users do have different versions of GHC on their machine, and actively use more than one? That said, generating |
Thank you everyone for the feedback so far, I really appreciate it! Amended proposal to propose Added to the proposal in the "power users" section that the new default behaviour can be changed via ~/.cabal.config Clarified that although absolute path is an option, we should instead just write the binary name for the reasons you mentioned. See the new Amendments section at the bottom for edit history. |
I actually have the opposite though, pinning to a ghc version should be an explicit thing not an implicit one. Especially if the pinned information is checked into version control. This becomes a hassle when you're working with a team on something but individual developers have different versions of ghc. This shouldn't matter for the majority of code out there. Also if 8.4.1 works there's absolutely no reason 8.4.2, 8.4.3 or 8.4.4 shouldn't work. So I think pinning of base as it does now is the much more sensible option. Requiring ghc also needlessly locks out other haskell Compilers. |
Completely agree, @ElvishJerricco's suggestion to write
This isn't the exact issue I'm thinking of, its the situation where someone tries out haskell, and then a couple months later come back and try to build their project again (maybe after a system update, since folks install ghc from their package manager sometimes) and it fails to build. The old version of ghc would still be on the path so if we pinned it, it would still work.
Sure, but the error message you get if your base bounds are wrong doesn't point you at all to what's wrong. For example, if everything else stays the same in my project but I upgrade my ghc which depends on a base version outside my bounds I get the following error:
I recognize this error as a ghc version incompatible with my stated bounds, but we should not expect beginners to know that. Maybe this could be solved with better error messages from cabal install somehow recognizing that this error is likely caused by a GHC upgrade and recommending appropriate action, but it would be best if it just never happened. @hvr for ideas on possibly improving the failed dependency solver messages? |
Thanks for the feedback :) Those are some good points you raise, let me see if I can provide my perspective on them.
I think this goes back to the comment that @ElvishJerricco made earlier in the thread that this depends on the type of project (library vs. executable): "Any libraries or build tools that someone wants to push to Hackage should be as relaxed and unpinned as reasonably possible. But when someone starts an end-use product, and not some library or infrastructure to be used by other projects, they invariably want a pinned down environment." This makes me think that maybe we should maybe pin the ghc for
That's a good point, although I think having several people agree on a compiler version is a pretty standard procedure when there's shared development on a project, and a good idea in general since there may be small discrepancies between versions anyways. And going back to the previous point, if you're working on a library it makes sense to support the widest range of compilers and dependency version bounds as possible, so the idea of only pinning for a binary package makes more sense.
I'm think I'm going to have to disagree with this point, pinning
I think this is a red herring, cabal already defaults to ghc as the compiler when initializing your project, so you need to perform additional configuration to get it to use a non-ghc compiler to build your project anyways. This proposal doesn't in any way prohibit you from choosing a different compiler afterwards if you want to use something other than ghc (and in fact with Let me know if I've misunderstood any of your points. |
So, what's the next step to take here? The majority of responses seem to be in favour, although I admit the number of responses wasn't huge. The point that @ElvishJerricco brought up about wanting to pin the version for products but not libraries was a great observation, I think we can address this by only pinnning for executables and not for libraries which are likely for publishing to hackage. How do folks feel about that? Lastly, if we decide that this is a desirable change, how can I help move this along? I haven't made any changes to cabal-install before but if someone is able to give me a bit of an intro and some code pointers I can look into making this change. Thanks! |
Something kind of like Stack's templates would probably be my preference for this. That way it's not a matter of defaults, but rather of just choosing the template you want. Though I do like cabal-install's Q&A style init, so whatever templating system used would need some way to do that. |
Or, for a super minimal change, there could just be a new question in that Q&A style init. |
So what happens when the pinned version is not installed anymore after a system upgrade? Do we at least try to build with the current one? Otherwise I think this makes for a much worse experience than we have now, because you have to go through all the project files and remove the |
@ElvishJerricco I would love to have something like Stack's templates for cabal-install. If I remember correctly they're going through a redesign and it's possible cabal could use the same underlying templates? I'm not sure though, I'll find out and follow up. @linearray Thanks for bringing that up, I can imagine a few ways of addressing this:
That being said, if you do a system upgrade you need to go through and update version bounds anyways, so it's still not a co-op. Also, in all cases I know of, doing a system upgrade leaves the old ghc (with version attached) on the PATH, so your project should continue building until you decide to update your project. Also, out of scope here but it works be great if there was a |
@ElvishJerricco re. new question: that could work, but a beginner would have no idea what that means, which kinda negates the problem I'm trying to solve :) |
Homebrew will leave the old version lying around until you decide to do a
I think we have to be careful not to create a problem where there was none before w.r.t. upgrades, especially now when they are so frequent. As stated above A (cheap) suggestion: Perhaps it would be better to not refuse compilation with the new A more comprehensive solution should at least combine updating |
@linearray thanks for the thoughtful comments 👍
Ah yes, forgot about that, its been a while. I wonder if that's the most common way of installing
So, the idea isn't to pin a particular path, just the compiler with the version number (such as
That's true of
Agreed, but given the points above I don't think this will happen in practice.
I'm not sure how the cabal developers would feel about this, it kinda defeats the purpose of
I completely agree. There should be a tool where you point it to a project directory and say what the new version of ghc you'd like to use would be and it would update your |
Overview
I recently documented all the steps you need to go through to get a working project from scratch using cabal-install, and one of the pain points I found was around specifying and pinning the compiler version.
Currently, running
cabal init
uses theghc
found on PATH to initialize the project, but does not pin the compiler version. As a consequence, its possible for changes in the global environment to break the build for a project (the dreaded non-reproducible build problem).There's actually nothing preventing cabal from offering by default "reproducible builds", by pinning the ghc version and using v2/new-build. In my opinion, upgrading to a new compiler for a project should be an explicit action, not implicit based on global environment configuration.
I propose that project initialization via cabal pins the ghc version by creating
cabal.project.local
cabal.project
containing awith-compiler
directive.Motivating Story
Happy Haskeller Holly is working on a project, everything builds and works great! She finishes up the project and some time later starts work on another project, noticing that there's a shiny new ghc version (woohoo!) that she wants to start using. So, she upgrades her compiler, starts working on a new project and everything is great. Later, she has a great idea for how to improve her first project, so she goes back to it, and surprise! It doesn't build anymore, and Holly become a sad Haskeller.
Who's developer experience does this improve?
Almost everyone, and especially beginners/casual users. Haskell tools have a reputation of being difficult to use (and in the past, this was very true) but as a community we've gotten much better at making things accessible to everyone, from beginners to experts. There are many points in the build tool design space, and a beginner for one reason or another may end up using any one of them. It is my opinion that whatever one they use they should have simple, consistent experience for getting from a fresh system to a working project, and that project should continue to work in the future.
"But what about the power users?"
One possible counter-argument to this is folks who have a complicated/non-standard workflow, and this would be an extra step they may need to undo/revert. My personal opinion is that the workflow that works the smoothest for newcomers should be the default, if you're experienced enough to set up a complicated workflow, then it's easy enough for you to work around it; beginners don't have the luxury of experience and familiarity :)
Amendment: In addition, this new default behaviour can be disabled in ~/.cabal/config.
What does this not address
This proposal does not address the case when you don't have the pinned ghc version installed. If you have a pinned ghc version it will not attempt to download it for you. An idea for how this problem could be solved is through an integration with ghcup, but that's another discussion.
Design
Prior Art
It is currently possible to pin the compiler version for a project via configure
cabal v2-configure -w ghc-8.4.4
. This is already what folks do, but thewith-compiler
option is buried in the docs and not mentioned in the Cabal Configuration Overview section or in the Quickstart despite it avoiding a lot of confusion and build errors for beginners (or even folks who haven't used Haskell in a while).#5658 (pending at time of writing) adds support for passing
--with-compiler
(-w
) tocabal init
which will pin the version of the compiler when the project is initialized, correction: this PR does not do any pinnning or write a project file.Changes
cabal init
by default writes acabal.project.local
cabal.project
containing awith-compiler
directive, taken from theghc
on the path (details below)cabal init
output contains info about whatghc
was selected (the full path) as well as where the configuration is written. This helps inform users that this option exists, what it does, and where to change it.Selecting ghc path
We can instead find out the exact version of
ghc
that's currently on the PATH viaghc --version
and then attempt to find the specific binary (usually also on the path and then symlinked toghc
). If we are unable to find it we could fallback to not pinning the version and printing a message.There are two options for pinning: either specify the full path to the executable, or specify just the executable name (
ghc-ver
).Amendment: The latter is preferred as different ghc installation mechanisms place the binary in different locations.
Amendments
2018-11-05 8:12PST
with-compiler
tocabal.project
instead ofcabal.project.local
-w
/--with-compiler
flag tocabal init
#5658 does not produce a project file.The text was updated successfully, but these errors were encountered: