haskell / cabal

Official upstream development repository for Cabal and cabal-install
https://haskell.org/cabal
Other
1.6k stars 690 forks source link

Produce a cabal.project file upon `cabal init` to pin the GHC version explicitly #10188

Open Kleidukos opened 1 month ago

Kleidukos commented 1 month ago

Context

After spending some time in the contact of beginners, a recurring thing has been noted: The GHC version is indirectly constrained by the bounds on the base library.

This is not a very common behaviour in other ecosystems, and each time I explain how this works, I feel like I am just describing a very weird and counter-intuitive situation instead of giving an actual good reason.

From a personal standpoint I also systematically write down:

packages: ./

with-compiler: ghc-9.8

in my new executable projects.

Compare the difference in user experience:

When exclusively relying on base bounds

Error: [Cabal-7107]
Could not resolve dependencies:
[__0] trying: myproject-0.1.0.0 (user goal)
[__1] next goal: base (dependency of myproject)
[__1] rejecting: base-4.18.2.1/installed-4.18.2.1 (conflict: myproject => base^>=4.19)
[__1] skipping: base; 4.20.0.1, 4.20.0.0 (has the same characteristics that caused the previous version to fail: excluded by constraint '^>=4.19' from 'myproject')
[__1] rejecting: base; 4.19.1.0, 4.19.0.0, 4.18.2.1, 4.18.2.0, 4.18.1.0, 4.18.0.0, 4.17.2.1, 4.17.2.0, 4.17.1.0, 4.17.0.0, 4.16.4.0, 4.16.3.0, 4.16.2.0, 4.16.1.0, 4.16.0.0, 4.15.1.0, 4.15.0.0, 4.14.3.0, 4.14.2.0, 4.14.1.0, 4.14.0.0, 4.13.0.0, 4.12.0.0, 4.11.1.0, 4.11.0.0, 4.10.1.0, 4.10.0.0, 4.9.1.0, 4.9.0.0, 4.8.2.0, 4.8.1.0, 4.8.0.0, 4.7.0.2, 4.7.0.1, 4.7.0.0, 4.6.0.1, 4.6.0.0, 4.5.1.0, 4.5.0.0, 4.4.1.0, 4.4.0.0, 4.3.1.0, 4.3.0.0, 4.2.0.2, 4.2.0.1, 4.2.0.0, 4.1.0.0, 4.0.0.0, 3.0.3.2, 3.0.3.1 (constraint from non-reinstallable package requires installed instance)
[__1] fail (backjumping, conflict set: base, myproject)
After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: base, myproject

When using with-compiler

Error: [Cabal-5490]
Cannot find the program 'ghc'. User-specified path 'ghc-9.12' does not refer to an executable and the program is not on the system path.

Moreover, with the error codes, we are able to provide better feedback to the user regarding the reason cabal fails. Even this infamous search engine gives relevant results:

Screenshot 2024-07-08 at 22-30-40 Cabal-5490 - Recherche Google


This RFC

The point of this RFC is to argue in favour of changing the behaviour of cabal init in two ways:

We can even add a link to the project file documentation as a comment in the first line.

The whole point is to improve a beginner's first steps in Haskell. Cloning a repository and getting a solver error when running cabal build is not people particularly enjoy, especially when they have to go on a wild goose chase to figure out which version of base is shipped with which version of ghc.

Should this RFC be accepted, I will implement it.

michaelpj commented 1 month ago

I'm not sure that with-compiler is necessarily a good mechanism for this. It takes a binary name, not any symbolic constraint that ensures you get a compiler with that version. This breaks e.g. on many distributions you just get ghc, no version prefix. So a project which assumes you get version-suffixed compilers will break on other machines.

We have impl(ghc) which actually checks the GHC version. It would be nice if we had more ways of interacting with that.

Also note that this is really a problem for packages. Doing this with with-compiler doesn't save you the moment you depend on a package that doesn't support your GHC. See e.g https://github.com/haskell/cabal/issues/9648

Kleidukos commented 1 month ago

You're indeed right, it's certainly my bias as a user of ghcup. :)

philderbeast commented 1 month ago

We have impl(ghc) which actually checks the GHC version. It would be nice if we had more ways of interacting with that.

Do we have something like Stack's user-message so that we could message the user?

if !(impl(ghc >= x.y.z) && impl(ghc < m))
  user-message: Can't find the expected compiler
michaelpj commented 1 month ago

@philderbeast we don't but it's discussed in https://github.com/haskell/cabal/issues/9648