Why is HLS asking ghcup to install GHC?

Occasionally when I’m using HLS (via emacs’s lsp mode) I see that in the background ghcup is installing some version of GHC that I don’t have. Often I don’t have enough free space, so it just dies. I’ve ended up with .ghcup/tmp containing 8 GB of temporary files from aborted installs!

I don’t understand why HLS is asking ghcup to install anything. lsp mode and HLS are working fine, so it doesn’t seem like I need a new version of GHC installed.

Why is it happening, and is there a way I can disable this behaviour?

(I’m currently using HLS 2.5.0.0 but it also happened with whichever version of HLS I was using before, too.)

That seems extremely weird. HLS does not call ghcup, it does call your build tool to get flag information but that’s about it.

The vscode extension does call ghcup to install HLS, but not GHC. Not that that’s relevant since you’re using Emacs.

1 Like

Oh, OK, thanks, how mysterious. Next time it happens I’ll do a pstree to try to determine exactly what process is causing ghcup to be run. It must be something to do with HLS because I only ever see this when using HLS (through lsp). That doesn’t mean it’s HLS that is responsible, of course. It could be something else in my emacs config that’s doing it …

Is it a stack project where you installed stack with ghcup? It looks like then stack will call ghcup sometimes. I think HLS calls something like stack setup, so conceivably in that situation it could trigger downloading GHC?

2 Likes

I have one stack-using project open, which is stan, and indeed I have stack installed via ghcup (although I don’t use stack myself). I don’t see anything in the current stan that would request ghc-9.4.7, which is what ghcup was trying to download, but perhaps this is indeed the problem. I’ll keep an eye on it.

Although if I do stack build in the stan directory it does try to download ghc-9.6.4, so maybe this is the root cause. I was pretty sure HLS was using cabal on this project though … It looks like I don’t have a hie.yaml here, so I am not certain …

If there is both cabal and stack configuration in a project and no hie.yaml, then we guess stack. Sounds like that’s the culprit.

2 Likes

That sounds pretty plausible but I don’t really understand what I’m seeing, because in the logs I see this from 10 minutes ago when I just tried (and posted my message):

2024-02-05T16:42:35.349366Z | Debug | executing command: cabal --builddir=/home/tom/.cache/hie-bios/dist-stan-624f6e53d42a862e637781e3061ca192 v2-repl --with-compiler /home/tom/.cache/hie-bios/wrapper-b54f81dea4c0e6d1626911c526bc4e36 --with-hc-pkg /home/tom/.cache/hie-bios/ghc-pkg-6ab590ecd05b25ce2522f0302b32bac5 lib:stan

I don’t see any evidence it has tried to use stack for anything and I definitely don’t have a hie.yaml.

The other variable is that stack needs to be on the path, if that could have changed.

Doesn’t look like it. Seems like it’s been there since October:

% ls -l $(which stack)
lrwxrwxrwx 1 tom tom 12 Oct 29 15:02 /home/tom/.ghcup/bin/stack -> stack-2.11.1

OK, I think I’ve seen enough to understand most of what’s going on now. Here’s pstree during the latest occurrence:

           |-screen(1428354)---emacs(1428356)-+-aspell(1526625)
           |                                  |-haskell-languag(1913455)-+-{haskell-languag}(1913785)
           |                                  |                          |-{haskell-languag}(1913786)
...
           |                                  |-stack(1965609)-+-sh(1965614)---ghcup(1965616)-+-{ghcup}(1965624)
           |                                  |                |                              |-{ghcup}(1965625)
...
           |                                  |                |-{stack}(1965610)
...
           |                                  |-{emacs}(1428408)
...

So ghcup is being called by stack which itself is being called by emacs.I would have expected to see it called by haskell-language-server, but maybe there’s some parent misattribution there. ghcup is trying to install ghc-9.4.7

% ps aux | grep '[^.]ghcu[p]'
tom      1965616 32.3  0.2 1073760360 23280 ?    Sl   19:17   0:15 ghcup run --ghc 9.4.7 --install

emacs's *Messages* gives a clue why 9.4.7 specifically:

         /home/tom/.ghcup/ghc/9.4.7/bin/ghc: getFileStatus: does not exist (No such file or directory)
Error: [S-6362]
No compiler found, expected minor version match with ghc-9.4.7 (x86_64-tinfo6-libc6-pre232) (based on resolver setting in /home/tom/.stack/global-project/stack.yaml).
To install the correct GHC into /home/tom/.stack/programs/x86_64-linux/, try running 'stack setup' or use the '--install-ghc' flag. To use your system GHC installation, run 'stack config set system-ghc --global true', or use the '--system-ghc' flag.

Try installing a more recent version of haskell-stack-ghc, and please open a bug report if the issue persists in the latest release.  Thanks!

and indeed:

% cat .stack/global-project/stack.yaml
...
packages: []
resolver: lts-21.18

LTS 21.18 is ghc-9.4.7. I don’t, however, understand why stack run through HLS is using stack/global-project/stack.yaml when there’s a stack.yaml in stan's top-level directory.

Anyway, the main mystery is resolved. I guess I should just use hie.yaml and ask for cabal. Thanks again for your help, @michaelpj.

Since going all in on ghcup, I’ve configured stack to only use the system ghc and not to install it with:

$ stack config set system-ghc true --global
$ stack config set install-ghc false --global
$ cat ~/.stack/config.yaml
...
system-ghc: true
install-ghc: false

I don’t see stack trying to install GHC anymore with this configuration.

2 Likes

Stack will use GHCup to manage versions of GHC if you have (a) customised Stack to do so (possibly by asking GHCup to customise Stack in that way on set up) and (b) not set Stack to try to use the version of GHC on the PATH (system-ghc: true) - see Configuration (project and global) - The Haskell Tool Stack. If you want Stack to manage versions of GHC directly, delete ghc-install.sh from the hooks directory in the Stack root directory (stack path --stack-root).

When GHCup is being used to manage versions of Stack, it puts a small exectuable named stack on the PATH that runs the specified version of Stack (also named stack). (As an aside, this interferes with Stack’s own management of versions of Stack.)

If you set system-ghc: true, Stack will try to use the GHC version on the PATH, if it is the correct version. If you set install-ghc: false and Stack is managing versions of GHC directly (not via GHCup), Stack will not try to install the correct version of GHC if it is not available.

EDIT: So, as @philderbeast rightly advises, if somebody is using GHCup to manage manually the version of GHC on the PATH and that user does not want Stack to fetch automatically (via GHCup or otherwise) GHC if the correct version is not available to Stack on the PATH, the user needs to configure Stack with system-ghc: true and install-ghc: false (either at the level of the individual project in stack.yaml or, more likely, globally in config.yaml).

1 Like

Thanks, I’ll do that!