Skip to content

haskell-language-server: build its closure in a Cabal-syntax 3.14 scope - #4

Open
hhefesto wants to merge 1 commit into
ekala-project:masterfrom
hhefesto:hls-ghc910
Open

hhefesto wants to merge 1 commit into
ekala-project:masterfrom
hhefesto:hls-ghc910

Conversation

@hhefesto

@hhefesto hhefesto commented Sep 8, 2026

Copy link
Copy Markdown

Follow-up to ekala-project/corepkgs#178 and #180: #178 said haskell-language-server built on the new ghc9103Binary set, and it did not. This makes it build, on the snapshot as it is.

Why it failed. HLS 2.13 pulls ormolu 0.8.0.2 and fourmolu 0.19.0.1, which want Cabal-syntax >= 3.14 && < 3.15, while GHC 9.10 bundles 3.12.1.0 (and 9.8 bundles 3.10.3.0). None of HLS, ghcide, ormolu, fourmolu, extensions or stan are in LTS 24.38; hackage2nix emits them as latest-Hackage defaults. Built against the bundled Cabal-syntax, the closure ends up with two instances and Cabal refuses to configure haskell-language-server.

Why here and not in corepkgs. corepkgs composes its compiler configuration before config.overlays.haskell, so anything the snapshot defines is redefined by this repo's overlay; an HLS override in configuration-ghc-9.10.x.nix is silently discarded (checked by evaluation with an lib.mkBefore overlay). haskell-packages.nix is the overlay this README reserves for per-package fixes, and it was empty.

What this does (nixpkgs' recipe from configuration-common.nix, "haskell-language-server section"):

  • Re-scopes the HLS closure (haskell-language-server, hls-plugin-api, ghcide, hlint, ormolu, fourmolu, lsp-types) with overrideScope onto Cabal-syntax_3_14_2_0 and Cabal_3_14_2_0, with extensions_0_1_1_0 (the Cabal-syntax 3.14 release; the default 0.1.0.2 wants Cabal 3.12), a jailbroken cabal-install-parsers (bound Cabal-syntax < 3.13), and ghc-paths kept on the bundled Cabal it only needs for Setup.hs.
  • Pairs Cabal_3_14_2_0 and Cabal_3_16_1_0 with their own Cabal-syntax instead of the bundled one.
  • Jailbreaks hw-fingertree (deepseq upper bound excludes 9.10's 1.5.1.0).
  • Sets enableSharedExecutables = true on HLS, as nixpkgs' configuration-nix.nix does: the first build compiled everything and then failed only in fixup, "RPATH of binary … contains a forbidden reference to /build/".

It applies to every compiler set, like nixpkgs' version; on 9.8.4 HLS is broken the same way today, so the default set cannot regress, but I only built the 9.10.3 set. No test-suite patches are needed because corepkgs' generic-builder defaults doCheck = false.

Checked (corepkgs at #180's branch + this branch, x86_64-linux):

  • haskell.packages.ghc9103Binary.haskell-language-server builds; --version2.13.0.0 (GHC: 9.10.3); --probe-tools finds cabal 3.16.1.0 and ghc 9.10.3.
  • Runtime closure holds one Cabal-syntax (3.14.2.0), one Cabal (3.14.2.0), extensions-0.1.1.0; ormolu, fourmolu, stylish-haskell, cabal-add and stan plugins are linked.
  • Inside a shellFor dev shell of a real project on that set, haskell-language-server srcCompleted (26 files worked, 0 files failed).
  • haskellPackages (9.8.4) and the project's own derivation are unchanged by the overlay.

Not included: the hlint plugin — HLS 2.13's own cabal file disables it on ghc ==9.10.* ("Hlint isn't compatible with GHC 9.10, and crashes in subtle ways"), so no override can bring it back on this compiler. Also not included: the HLS bindist wrapper nixpkgs installs (postInstall in its configuration-nix.nix) that checks the runtime GHC's ABI hashes; worth adding if you want the haskell-language-server-9.10.3 alias and the mismatch guard.

HLS 2.13's formatters, ormolu 0.8 and fourmolu 0.19, need Cabal-syntax
3.14 where the compilers bundle 3.10 (GHC 9.8) or 3.12 (GHC 9.10). Built
against the bundled one, the closure carries two Cabal-syntax instances and
Cabal refuses to configure haskell-language-server. Re-scope the closure
(haskell-language-server, hls-plugin-api, ghcide, hlint, ormolu, fourmolu,
lsp-types) onto Cabal-syntax and Cabal 3.14.2.0, with extensions 0.1.1.0
(the Cabal-syntax 3.14 release), a jailbroken cabal-install-parsers, and
ghc-paths kept on the bundled Cabal it only needs for Setup.hs. This is
nixpkgs' recipe from configuration-common.nix.

Also pair the versioned Cabal_3_14_2_0 and Cabal_3_16_1_0 with their own
Cabal-syntax, jailbreak hw-fingertree's deepseq bound for GHC 9.10, and
let HLS link its executables dynamically, without which the fixup check
finds an RPATH into /build.

Verified on haskell.packages.ghc9103Binary: haskell-language-server
2.13.0.0 builds, reports GHC 9.10.3, and its closure holds a single
Cabal-syntax (3.14.2.0).
@qweered

qweered commented Sep 8, 2026

Copy link
Copy Markdown

I think this should also be in corepkgs cc @jonringer, instead we should drop most packages from ekala-project/corepkgs#101, its too opinionated and at this point we should advise people to use ekapkgs instead

@jonringer

Copy link
Copy Markdown
Contributor

I think this should also be in corepkgs cc @jonringer, instead we should drop most packages from ekala-project/corepkgs#101, its too opinionated and at this point we should advise people to use ekapkgs instead

I mean, you're probably right. I just don't want you to be right xD

@jonringer

Copy link
Copy Markdown
Contributor

If we are going to do removals, sooner would be better than later

hhefesto added a commit to hhefesto/stand-in-language that referenced this pull request Sep 8, 2026
The Nix build moves to the ekala package ecosystem: corepkgs for the base
system and the compiler, haskell-pkgs for the Hackage snapshot (Stackage
LTS 24). flake-parts, haskell-flake, flake-compat and the nixpkgs input go;
the flake has two inputs and uses `corepkgs.lib.mkFlake`. Everything, the
tools included, is built with one compiler, GHC 9.10.3.

GHC stays at 9.10.3: corepkgs carried only 9.8.4 and 9.0.2 bindists, so the
9.10.3 bindist and a `haskell.packages.ghc9103Binary` set were added
upstream (ekala-project/corepkgs#178, corrected in #180), with the bindists'
terminfo made to link (without that, nothing using haskeline links). The
corepkgs input is `github:ekala-project/corepkgs`. `cabal-version: 3.12`
and the sources are unchanged.

haskell-language-server needs its whole closure built in one Cabal-syntax
3.14 scope (ormolu, fourmolu, cabal-add and the server want 3.14 where GHC
9.10 bundles 3.12, and `extensions` is pinned to 3.12; Cabal refuses the
mix). That is ekala-project/haskell-pkgs#4; until it lands, the
haskell-pkgs input points at the fork branch hhefesto/haskell-pkgs/hls-ghc910,
and then moves back to ekala-project/haskell-pkgs.

Every entry point is preserved: `nix build`, `nix run .`/`.#repl`/`.#lsp`/
`.#format`/`.#format-lint`/`.#push-cachix`, the per-executable apps CI and
the Emacs mode use, `nix develop`, `nix flake check`, `nix-build` and
`nix-shell`. The default dev shell is the minimum that builds the project
(GHC and cabal-install); `nix develop .#full` adds haskell-language-server,
hlint, stylish-haskell and ghcid; hoogle is no longer built for either.

The Nix code lives in nix/: haskell.nix names the compiler and the tools,
telomare.nix is the package policy (built from `cabal sdist`, tests on, no
haddock or profiling, as haskell-flake did), tools.nix the shell apps,
devshell.nix, and pins.nix/pkgs.nix/legacy.nix for default.nix and
shell.nix, which read the pins from flake.lock. The package expression is a
checked-in cabal2nix file: ekapkgs does not define `cabal2nix-unwrapped`,
so `callCabal2nix` cannot evaluate; a dependency missing from the file
fails `Setup configure` loudly, and nothing is imported from a derivation
any more. Shell apps carry an explicit shellcheck check phase, since
`writeShellApplication`'s default refers to a `shellcheck-minimal` ekapkgs
does not define; shellcheck and cachix come from the 9.10.3 set rather than
haskell-pkgs' 9.8.4-built top level. The apps use `gitMinimal`: they only
list and read tracked files, and the full git brings its manual into the
closure. `cabal-install` is marked unbroken (the snapshot flags it with no
broken dependency) and built against the snapshot's Cabal 3.16, which
cabal-install 3.16 requires and GHC 9.10's bundled 3.12 is not.
`apps.telomare-lsp` carries the version stamp like `apps.lsp`; `systems`
is x86_64-linux until corepkgs marks aarch64-linux supported. CI pulls
from `ekala-corepkgs` too and accepts the flake's nixConfig.

Verified on x86_64-linux: the package builds from the sdist tarball with
its five suites passing; `nix run .#telomare-repl -- --expr 'succ 7'` gives
8; `nix-build` yields the flake's store path; `nix develop .#full -c
haskell-language-server --version` reports 2.13.0.0 on GHC 9.10.3 and the
server typechecks the 26 modules under src/; against the nixpkgs build of
master, `tictactoe.telc`, the simpleplus run transcript, its certificate
and its meter are byte-identical.
@qweered

qweered commented Sep 8, 2026

Copy link
Copy Markdown

If we are going to do removals, sooner would be better than later

I'll do it tomorrow if everything will be ok, already removed x86_64-darwin remnants

hhefesto added a commit to hhefesto/stand-in-language that referenced this pull request Sep 9, 2026
The Nix build moves to the ekala package ecosystem: corepkgs for the base
system and the compiler, haskell-pkgs for the Hackage snapshot (Stackage
LTS 24). flake-parts, haskell-flake, flake-compat and the nixpkgs input go;
the flake has two inputs and uses `corepkgs.lib.mkFlake`. Everything, the
tools included, is built with one compiler, GHC 9.10.3.

GHC stays at 9.10.3: corepkgs carried only 9.8.4 and 9.0.2 bindists, so the
9.10.3 bindist and a `haskell.packages.ghc9103Binary` set were added
upstream (ekala-project/corepkgs#178, corrected in #180), with the bindists'
terminfo made to link (without that, nothing using haskeline links). The
corepkgs input is `github:ekala-project/corepkgs`. `cabal-version: 3.12`
and the sources are unchanged.

haskell-language-server needs its whole closure built in one Cabal-syntax
3.14 scope (ormolu, fourmolu, cabal-add and the server want 3.14 where GHC
9.10 bundles 3.12, and `extensions` is pinned to 3.12; Cabal refuses the
mix). nix/haskell.nix carries that override, the recipe of nixpkgs'
configuration-common.nix and of ekala-project/haskell-pkgs#4; it goes when
the fix lands upstream, in haskell-pkgs or corepkgs. Both inputs point at
ekala-project. corepkgs' treefmt-nix input drags nixpkgs into the lock for
a formatter this flake never evaluates; it follows nix-lib instead, so the
lock and the cache push carry no nixpkgs checkout.

Every entry point is preserved: `nix build`, `nix run .`/`.#repl`/`.#lsp`/
`.#format`/`.#format-lint`/`.#push-cachix`, the per-executable apps CI and
the Emacs mode use, `nix develop`, `nix flake check`, `nix-build` and
`nix-shell`. The default dev shell is the minimum that builds the project
(GHC and cabal-install); `nix develop .#full` adds haskell-language-server,
hlint, stylish-haskell and ghcid; hoogle is no longer built for either.

The Nix code lives in nix/: haskell.nix names the compiler and the tools,
telomare.nix is the package policy (built from `cabal sdist`, tests on, no
haddock or profiling, as haskell-flake did), tools.nix the shell apps,
devshell.nix, and pins.nix/pkgs.nix/legacy.nix for default.nix and
shell.nix, which read the pins from flake.lock. The package expression is a
checked-in cabal2nix file: ekapkgs does not define `cabal2nix-unwrapped`,
so `callCabal2nix` cannot evaluate; a dependency missing from the file
fails `Setup configure` loudly, and nothing is imported from a derivation
any more. Shell apps carry an explicit shellcheck check phase, since
`writeShellApplication`'s default refers to a `shellcheck-minimal` ekapkgs
does not define; shellcheck and cachix come from the 9.10.3 set rather than
haskell-pkgs' 9.8.4-built top level. The apps use `gitMinimal`: they only
list and read tracked files, and the full git brings its manual into the
closure. CI's install-nix-action and cachix-action move to v31 and v17. `cabal-install` is marked unbroken (the snapshot flags it with no
broken dependency) and built against the snapshot's Cabal 3.16, which
cabal-install 3.16 requires and GHC 9.10's bundled 3.12 is not.
`apps.telomare-lsp` carries the version stamp like `apps.lsp`; `systems`
is x86_64-linux until corepkgs marks aarch64-linux supported. CI pulls
from `ekala-corepkgs` too and accepts the flake's nixConfig.

Verified on x86_64-linux: the package builds from the sdist tarball with
its five suites passing; `nix run .#telomare-repl -- --expr 'succ 7'` gives
8; `nix-build` yields the flake's store path; `nix develop .#full -c
haskell-language-server --version` reports 2.13.0.0 on GHC 9.10.3 and the
server typechecks the 26 modules under src/; against the nixpkgs build of
master, `tictactoe.telc`, the simpleplus run transcript, its certificate
and its meter are byte-identical.
hhefesto added a commit to hhefesto/stand-in-language that referenced this pull request Sep 15, 2026
The Nix build moves to the ekala package ecosystem: corepkgs for the base
system and the compiler, haskell-pkgs for the Hackage snapshot (Stackage
LTS 24). flake-parts, haskell-flake, flake-compat and the nixpkgs input go;
the flake has two inputs and uses `corepkgs.lib.mkFlake`. The project and
every packaged Haskell tool are built with one compiler, GHC 9.10.3.

GHC stays at 9.10.3: corepkgs carried only 9.8.4 and 9.0.2 bindists, so the
9.10.3 bindist and a `haskell.packages.ghc9103Binary` set were added
upstream (ekala-project/corepkgs#178, corrected in #180), with the bindists'
terminfo made to link. `cabal-version: 3.12` and the sources are unchanged.

haskell-language-server needs its whole closure built in one Cabal-syntax
3.14 scope (ormolu, fourmolu, cabal-add and the server want 3.14 where GHC
9.10 bundles 3.12). nix/haskell.nix carries that override, the recipe of
nixpkgs' configuration-common.nix and of ekala-project/haskell-pkgs#4; it
goes when the fix lands upstream. Both inputs point at ekala-project.
corepkgs' treefmt-nix input drags nixpkgs into the lock for a formatter this
flake never evaluates; it follows nix-lib instead, so the lock and the cache
push carry no nixpkgs checkout.

Every entry point is preserved: `nix build`, `nix run .`/`.#repl`/`.#lsp`/
`.#format`/`.#format-lint`/`.#push-cachix`, the per-executable apps CI and
the Emacs mode use, `nix develop`, `nix flake check`, `nix-build` and
`nix-shell`. The default dev shell is the minimum that builds the project
(GHC and cabal-install); `nix develop .#full` adds haskell-language-server,
hlint, stylish-haskell and ghcid; hoogle is no longer built for either.

The Nix code lives in nix/: haskell.nix names the compiler and the tools,
telomare.nix is the package policy (built from `cabal sdist`, tests on, no
haddock or profiling, as haskell-flake did), tools.nix the shell apps,
devshell.nix, and pins.nix/pkgs.nix/legacy.nix for default.nix and
shell.nix, which read the pins from flake.lock. The package expression is a
checked-in cabal2nix file: ekapkgs does not define `cabal2nix-unwrapped`,
so `callCabal2nix` cannot evaluate; a dependency missing from the file
fails `Setup configure`, and nothing is imported from a derivation any
more. Shell apps carry an explicit shellcheck check phase, since
`writeShellApplication`'s default refers to a `shellcheck-minimal` ekapkgs
does not define; shellcheck comes from the 9.10.3 set rather than
haskell-pkgs' 9.8.4-built top level. `cabal-install` is marked unbroken
(the snapshot flags it with no broken dependency) and built against the
snapshot's Cabal 3.16, which it requires. The apps use `gitMinimal`: they
only list and read tracked files.

`nix run .#push-cachix`, the maintainers' tool, now publishes every declared
dev shell with its `nix develop` environment closure (so the full shell's
HLS and editor tools reach the cache) and is built and shellchecked by
`nix flake check`. It uses the cachix and the nix on the caller's PATH:
the snapshot's cachix does not build (its amazonka 2.0 predates GHC 9.8),
and corepkgs' Nix is a from-source build nothing else needs.

`apps.telomare-lsp` carries the version stamp like `apps.lsp`; `systems`
is x86_64-linux until corepkgs marks aarch64-linux supported. CI pulls
from `ekala-corepkgs` instead of `nix-community`, accepts the flake's
nixConfig, and moves install-nix-action and cachix-action to v31 and v17.

Verified on x86_64-linux (corepkgs c3bf28c4, haskell-pkgs 427f504a): the
package builds from the sdist tarball with its five suites passing;
`nix run .#telomare-repl -- --expr 'succ 7'` gives 8; `nix-build` yields
the flake's store path; `nix develop .#full -c haskell-language-server
--version` reports 2.13.0.0 on GHC 9.10.3 and the server typechecks the
26 modules under src/; against the nixpkgs build of master,
`tictactoe.telc`, the simpleplus run transcript, its certificate and its
meter are byte-identical.
hhefesto added a commit to hhefesto/stand-in-language that referenced this pull request Sep 15, 2026
The Nix build moves to the ekala package ecosystem: corepkgs for the base
system and the compiler, haskell-pkgs for the Hackage snapshot (Stackage
LTS 24). flake-parts, haskell-flake, flake-compat and the nixpkgs input go;
the flake has two inputs and uses `corepkgs.lib.mkFlake`. The project and
every packaged Haskell tool are built with one compiler, GHC 9.10.3.

GHC stays at 9.10.3: corepkgs carried only 9.8.4 and 9.0.2 bindists, so the
9.10.3 bindist and a `haskell.packages.ghc9103Binary` set were added
upstream (ekala-project/corepkgs#178, corrected in #180), with the bindists'
terminfo made to link. `cabal-version: 3.12` and the sources are unchanged.

haskell-language-server needs its whole closure built in one Cabal-syntax
3.14 scope (ormolu, fourmolu, cabal-add and the server want 3.14 where GHC
9.10 bundles 3.12). nix/haskell.nix carries that override, the recipe of
nixpkgs' configuration-common.nix and of ekala-project/haskell-pkgs#4; it
goes when the fix lands upstream. Both inputs point at ekala-project.
corepkgs' treefmt-nix input drags nixpkgs into the lock for a formatter this
flake never evaluates; it follows nix-lib instead, so the lock and the cache
push carry no nixpkgs checkout.

Every entry point is preserved: `nix build`, `nix run .`/`.#repl`/`.#lsp`/
`.#format`/`.#format-lint`/`.#push-cachix`, the per-executable apps CI and
the Emacs mode use, `nix develop`, `nix flake check`, `nix-build` and
`nix-shell`. The default dev shell is the minimum that builds the project
(GHC and cabal-install); `nix develop .#full` adds haskell-language-server,
hlint, stylish-haskell and ghcid; hoogle is no longer built for either.

The Nix code lives in nix/: haskell.nix names the compiler and the tools,
telomare.nix is the package policy (built from `cabal sdist`, tests on, no
haddock or profiling, as haskell-flake did), tools.nix the shell apps,
devshell.nix, and pins.nix/pkgs.nix/legacy.nix for default.nix and
shell.nix, which read the pins from flake.lock. The package expression is a
checked-in cabal2nix file: ekapkgs does not define `cabal2nix-unwrapped`,
so `callCabal2nix` cannot evaluate; a dependency missing from the file
fails `Setup configure`, and nothing is imported from a derivation any
more. Shell apps carry an explicit shellcheck check phase, since
`writeShellApplication`'s default refers to a `shellcheck-minimal` ekapkgs
does not define; shellcheck comes from the 9.10.3 set rather than
haskell-pkgs' 9.8.4-built top level. `cabal-install` is marked unbroken
(the snapshot flags it with no broken dependency) and built against the
snapshot's Cabal 3.16, which it requires. The apps use `gitMinimal`: they
only list and read tracked files.

`nix run .#push-cachix`, the maintainers' tool, now publishes every declared
dev shell with its `nix develop` environment closure (so the full shell's
HLS and editor tools reach the cache) and is built and shellchecked by
`nix flake check`. It uses the cachix and the nix on the caller's PATH:
the snapshot's cachix does not build (its amazonka 2.0 predates GHC 9.8),
and corepkgs' Nix is a from-source build nothing else needs.

`apps.telomare-lsp` carries the version stamp like `apps.lsp`; `systems`
is x86_64-linux until corepkgs marks aarch64-linux supported. CI pulls
from `ekala-corepkgs` instead of `nix-community`, accepts the flake's
nixConfig, and moves install-nix-action and cachix-action to v31 and v17.

Verified on x86_64-linux (corepkgs c3bf28c4, haskell-pkgs 427f504a): the
package builds from the sdist tarball with its five suites passing;
`nix run .#telomare-repl -- --expr 'succ 7'` gives 8; `nix-build` yields
the flake's store path; `nix develop .#full -c haskell-language-server
--version` reports 2.13.0.0 on GHC 9.10.3 and the server typechecks the
26 modules under src/; against the nixpkgs build of master,
`tictactoe.telc`, the simpleplus run transcript, its certificate and its
meter are byte-identical.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants