-
Notifications
You must be signed in to change notification settings - Fork 725
Description
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 the ghc 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.localcabal.project containing a with-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 the with-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) to cabal 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 initby default writes acabal.project.localcabal.projectcontaining awith-compilerdirective, taken from theghcon the path (details below)cabal initoutput contains info about whatghcwas 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.- Documentation is added to the cabal website, user docs, etc. explaining what this is, and step-by-step instructions for how to upgrade to a new ghc version.
- Amendment: The new default behaviour can be disabled by a change to ~/.cabal/config.
Selecting ghc path
We can instead find out the exact version of ghc that's currently on the PATH via ghc --version and then attempt to find the specific binary (usually also on the path and then symlinked to ghc). 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
- Write
with-compilertocabal.projectinstead ofcabal.project.local - Correction, Add
-w/--with-compilerflag tocabal init#5658 does not produce a project file. - New default behaviour can be disabled in ~/.cabal/config
- Clarified that only specifying the name of the binary is preferred over the full path.