Skip to content

Commit 96ea854

Browse files
authored
Nix flake fix dev shells (#2655)
* nix: ghc92: ignore broken plugins * nix: use current ghc for tools in the shell Theses tools are pulled in the shell, but we don't need them to match the GHC version used for development. Said otherwise, as long as we use a working `cabal-install` to build with GHC 9.2, we don't care if that cabal-install was built with GHC 8.10. This gives more chance for theses tools to work and be in the binary cache of nixpkgs. * nix: disable shake-bench for ghc921 * nix: fix ghc 9.2 shell * nix: explicit cabal project in devShell Using alias, we get the "correct" behavior when typing `cabal build` in the nix-shell, it points to the current cabal-project file. * nix: remove special case for different ghc versions * nix: move implicit-hie-cradle as a flake input * nix: restore dev shell This commit restores a working behavior for `nix-shell` or `nix develop`, for all supported GHC versions. When entering a `nix-shell`, or `nix develop .#haskell-language-server-ghcXxX-dev` you will get an environment with all the dependencies needed to run `cabal build`. Haskell dependencies will be built by cabal instead of nix. This may be more robust compared to a shell where dependencies are built by nix: - It won't try to build any dependency with nix. This mean that it won't benefit from nix caching, but on the other hand, it will perfectly match the cabal plan. - The nix shell may fail to start if an (possibly unneeded) dependency was failing to build. Entering nix-shell also generates an alias command `cabal_project` which runs cabal with the correct project file if needed (e.g. for GHC 9.0 and 9.2). Users are notified with a message when entering the shell. The old behavior (i.e. where dependencies are built with nix) is still available with `nix develop .#haskell-language-server-xxx-dev-nix` (i.e. suffix the name of the shell with `-nix`). * nix: New entries which build all target at once All HLS version can be built with `nix build .#all-haskell-language-server`, and all development shells with `nix build .#all-dev-shells`. I had to workaround a limitation in `nix build` which is not able to build multiples targets, instead I used linkFarmFromDrvs. All packages and shells are now named with a unique package name containing the GHC version. * nix: Build all devShells and all binaries in CI * nix: build HLS with dynamic linking Related to #2668. This fixs the build, however, because now HLS is dynamicly linked, it pulls GHC as a dependency. The uncompressed closure size is now `~6GiB`. * nix; fix CI command * nix: only build dev shell with nix packages for current GHC version * Another tentative to fix the build * fix: Eval and alternate number format works with ghc 9.2 * fix CI build * ANother tentative fix
1 parent 34e9914 commit 96ea854

File tree

5 files changed

+146
-47
lines changed

5 files changed

+146
-47
lines changed

Diff for: .github/workflows/nix.yml

+8-4
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,19 @@ jobs:
103103
authToken: ${{ secrets.HLS_CACHIX_AUTH_TOKEN }}
104104
- name: Build development shell
105105
run: nix develop --print-build-logs --profile dev
106-
- name: Build development shell (GHC 9.0.1)
107-
run: nix develop --print-build-logs .#haskell-language-server-901-dev --profile dev
106+
- name: Build all development shell (without nix dependencies)
107+
run: nix develop --print-build-logs .#all-simple-dev-shells --profile dev
108+
# We only build nix dev shell for current GHC version because some are
109+
# failing with different GHC version on darwin.
110+
- name: Build development shell with nix dependencies for current GHC version
111+
run: nix develop --print-build-logs .#all-nix-dev-shells --profile dev
108112
- name: Push development shell
109113
if: ${{ env.HAS_TOKEN == 'true' }}
110114
run: cachix push haskell-language-server dev
111115
- name: Build binaries
112116
run: nix build --print-build-logs
113-
- name: Build binaries (GHC 9.0.1)
114-
run: nix build --print-build-logs .#haskell-language-server-901
117+
- name: Build all binaries
118+
run: nix build --print-build-logs .#all-haskell-language-server
115119
- name: Push binaries
116120
if: ${{ env.HAS_TOKEN == 'true' }}
117121
run: nix path-info --json | jq -r '.[].path' | cachix push haskell-language-server

Diff for: configuration-ghc-901.nix

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ let
1010
hpkgsOverride = hself: hsuper:
1111
with pkgs.haskell.lib;
1212
{
13+
hlsDisabledPlugins = disabledPlugins;
14+
1315
fourmolu = hself.fourmolu_0_4_0_0;
1416
primitive-extras = hself.primitive-extras_0_10_1_2;
1517

Diff for: configuration-ghc-921.nix

+14-3
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,39 @@ let
55
disabledPlugins = [
66
"hls-brittany-plugin"
77
"hls-stylish-haskell-plugin"
8+
"hls-hlint-plugin"
9+
"hls-haddock-comments-plugin"
10+
"hls-tactics-plugin"
11+
# That one is not technically a plugin, but by putting it in this list, we
12+
# get it removed from the top level list of requirement and it is not pull
13+
# in the nix shell.
14+
"shake-bench"
815
];
916

1017
hpkgsOverride = hself: hsuper:
1118
with pkgs.haskell.lib;
1219
{
20+
hlsDisabledPlugins = disabledPlugins;
21+
1322
fourmolu = hself.callCabal2nix "fourmolu" inputs.fourmolu {};
1423
primitive-extras = hself.primitive-extras_0_10_1_2;
1524
ghc-exactprint = hself.callCabal2nix "ghc-exactprint" inputs.ghc-exactprint {};
1625
constraints-extras = hself.callCabal2nix "constraints-extras" inputs.constraints-extras {};
1726
retrie = hself.callCabal2nix "retrie" inputs.retrie {};
27+
28+
# Hlint is still broken
1829
hlint = doJailbreak (hself.callCabal2nix "hlint" inputs.hlint {});
30+
hiedb = hself.hiedb_0_4_1_0;
1931

2032
# Re-generate HLS drv excluding some plugins
2133
haskell-language-server =
2234
hself.callCabal2nixWithOptions "haskell-language-server" ./.
2335
(pkgs.lib.concatStringsSep " " [
2436
"-f-brittany"
25-
"-f-stylishhaskell"
37+
"-f-stylishHaskell"
2638
"-f-hlint"
2739
"-f-haddockComments"
28-
"-f-alternateNumberFormat"
29-
"-f-eval"
40+
"-f-tactics"
3041
]) { };
3142

3243
# YOLO

Diff for: flake.lock

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: flake.nix

+109-40
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
url = "https://hackage.haskell.org/package/hlint-3.3.6/hlint-3.3.6.tar.gz";
5656
flake = false;
5757
};
58+
implicit-hie-cradle = {
59+
url = "https://hackage.haskell.org/package/implicit-hie-cradle-0.3.0.5/implicit-hie-cradle-0.3.0.5.tar.gz";
60+
flake = false;
61+
};
5862
};
5963
outputs =
6064
inputs@{ self, nixpkgs, flake-compat, flake-utils, pre-commit-hooks, gitignore, ... }:
@@ -113,11 +117,7 @@
113117
lsp-types = hsuper.callCabal2nix "lsp-types" inputs.lsp-types {};
114118
lsp-test = hsuper.callCabal2nix "lsp-test" inputs.lsp-test {};
115119

116-
implicit-hie-cradle = hself.callCabal2nix "implicit-hie-cradle"
117-
(builtins.fetchTarball {
118-
url = "https://hackage.haskell.org/package/implicit-hie-cradle-0.3.0.5/implicit-hie-cradle-0.3.0.5.tar.gz";
119-
sha256 = "15a7g9x6cjk2b92hb2wilxx4550msxp1pmk5a2shiva821qaxnfq";
120-
}) { };
120+
implicit-hie-cradle = hself.callCabal2nix "implicit-hie-cradle" inputs.implicit-hie-cradle {};
121121

122122
# https://github.com/NixOS/nixpkgs/issues/140774
123123
ormolu =
@@ -236,76 +236,145 @@
236236
dontInstall = true;
237237
};
238238

239+
mkDevShell = hpkgs: cabalProject: with pkgs; mkShell {
240+
name = "haskell-language-server-dev-ghc${hpkgs.ghc.version}";
241+
# For theses tools packages, we use ghcDefault
242+
# This removes a rebuild with a different GHC version
243+
# Theses programs are tools, used as binary, independently of the
244+
# version of GHC.
245+
# The drawback of this approach is that our shell may pull two GHC
246+
# version in scope (the default one, and the one defined in
247+
# `hpkgs`.)
248+
# The advantage is that we won't have to rebuild theses tools (and
249+
# dependencies) with a recent GHC which may not be supported by
250+
# them.
251+
buildInputs = [
252+
# our compiling toolchain
253+
hpkgs.ghc
254+
pkgs.cabal-install
255+
# @guibou: I'm not sure hie-bios is needed
256+
ghcDefault.hie-bios
257+
# Dependencies needed to build some parts of hackage
258+
gmp zlib ncurses
259+
# Changelog tooling
260+
(gen-hls-changelogs ghcDefault)
261+
# For the documentation
262+
pythonWithPackages
263+
# @guibou: I'm not sure this is needed.
264+
hlint
265+
ghcDefault.opentelemetry-extra
266+
capstone tracy
267+
# ormolu
268+
# stylish-haskell
269+
];
270+
271+
272+
shellHook = ''
273+
# @guibou: I'm not sure theses lines are needed
274+
export LD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
275+
export DYLD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
276+
export PATH=$PATH:$HOME/.local/bin
277+
278+
# Enable the shell hooks
279+
${(pre-commit-check ghcDefault).shellHook}
280+
281+
# If the cabal project file is not the default one.
282+
# Print a warning and generate an alias.
283+
if [ ${cabalProject} != "cabal.project" ]
284+
then
285+
echo "Cabal won't be able to build your project without using the project file "${cabalProject}", such as:"
286+
echo " cabal --project-file=${cabalProject}"
287+
echo "An alias "cabal_project" is available. Use it like:"
288+
echo " cabal_project build"
289+
290+
alias cabal_project='cabal --project-file=${cabalProject}'
291+
fi
292+
'';
293+
};
294+
239295
# Create a development shell of hls project
240296
# See https://github.com/NixOS/nixpkgs/blob/5d4a430472cafada97888cc80672fab255231f57/pkgs/development/haskell-modules/make-package-set.nix#L319
241-
mkDevShell = hpkgs:
297+
mkDevShellWithNixDeps = hpkgs: cabalProject:
242298
with pkgs;
299+
let simpleShell = mkDevShell hpkgs cabalProject;
300+
in
243301
hpkgs.shellFor {
302+
name = "haskell-language-server-dev-nix-ghc${hpkgs.ghc.version}";
303+
inherit (simpleShell) shellHook buildInputs;
304+
244305
doBenchmark = true;
245306
packages = p:
246307
with builtins;
247308
map (name: p.${name}) (attrNames
248-
(if hpkgs.ghc.version == "9.0.1" then
249-
removeAttrs hlsSources ghc901Config.disabledPlugins
250-
else if hpkgs.ghc.version == "9.2.1" then
251-
removeAttrs hlsSources ghc921Config.disabledPlugins
252-
else
253-
hlsSources));
254-
buildInputs = [ gmp zlib ncurses capstone tracy (gen-hls-changelogs hpkgs) pythonWithPackages ]
255-
++ (with hpkgs; [
256-
cabal-install
257-
hie-bios
258-
hlint
259-
# ormolu
260-
# stylish-haskell
261-
opentelemetry-extra
262-
]);
309+
# Disable dependencies should not be part of the shell.
310+
(removeAttrs hlsSources (hpkgs.hlsDisabledPlugins or [])));
263311

264312
src = null;
265-
shellHook = ''
266-
export LD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
267-
export DYLD_LIBRARY_PATH=${gmp}/lib:${zlib}/lib:${ncurses}/lib:${capstone}/lib
268-
export PATH=$PATH:$HOME/.local/bin
269-
${if hpkgs.ghc.version != "9.0.1" then (pre-commit-check hpkgs).shellHook else ""}
270-
'';
271313
};
272314
# Create a hls executable
273315
# Copied from https://github.com/NixOS/nixpkgs/blob/210784b7c8f3d926b7db73bdad085f4dc5d79418/pkgs/development/tools/haskell/haskell-language-server/withWrapper.nix#L16
274316
mkExe = hpkgs:
275317
with pkgs.haskell.lib;
276-
justStaticExecutables (overrideCabal hpkgs.haskell-language-server
318+
(enableSharedExecutables (overrideCabal hpkgs.haskell-language-server
277319
(_: {
278320
postInstall = ''
279-
remove-references-to -t ${hpkgs.ghc} $out/bin/haskell-language-server
280321
remove-references-to -t ${hpkgs.shake.data} $out/bin/haskell-language-server
281322
remove-references-to -t ${hpkgs.js-jquery.data} $out/bin/haskell-language-server
282323
remove-references-to -t ${hpkgs.js-dgtable.data} $out/bin/haskell-language-server
283324
remove-references-to -t ${hpkgs.js-flot.data} $out/bin/haskell-language-server
284325
'';
285-
}));
326+
}))).overrideAttrs(old: {
327+
pname = old.pname + "-ghc${hpkgs.ghc.version}";
328+
});
286329
in with pkgs; rec {
330+
# Developement shell with only compiler
331+
simpleDevShells = {
332+
haskell-language-server-dev = mkDevShell ghcDefault "cabal.project";
333+
haskell-language-server-884-dev = mkDevShell ghc884 "cabal.project";
334+
haskell-language-server-8107-dev = mkDevShell ghc8107 "cabal.project";
335+
haskell-language-server-901-dev = mkDevShell ghc901 "cabal-ghc90.project";
336+
haskell-language-server-921-dev = mkDevShell ghc921 "cabal-ghc921.project";
337+
};
287338

288-
packages = {
289-
# dev shell
290-
haskell-language-server-dev = mkDevShell ghcDefault;
291-
haskell-language-server-884-dev = mkDevShell ghc884;
292-
haskell-language-server-8107-dev = mkDevShell ghc8107;
293-
haskell-language-server-901-dev = mkDevShell ghc901;
294-
haskell-language-server-921-dev = mkDevShell ghc921;
339+
# Developement shell, haskell packages are also provided by nix
340+
nixDevShells = {
341+
haskell-language-server-dev-nix = mkDevShellWithNixDeps ghcDefault "cabal.project";
342+
haskell-language-server-884-dev-nix = mkDevShellWithNixDeps ghc884 "cabal.project";
343+
haskell-language-server-8107-dev-nix = mkDevShellWithNixDeps ghc8107 "cabal.project";
344+
haskell-language-server-901-dev-nix = mkDevShellWithNixDeps ghc901 "cabal-ghc90.project";
345+
haskell-language-server-921-dev-nix = mkDevShellWithNixDeps ghc921 "cabal-ghc921.project";
346+
};
295347

296-
# hls package
348+
allPackages = {
297349
haskell-language-server = mkExe ghcDefault;
298350
haskell-language-server-884 = mkExe ghc884;
299351
haskell-language-server-8107 = mkExe ghc8107;
300352
haskell-language-server-901 = mkExe ghc901;
301353
haskell-language-server-921 = mkExe ghc921;
354+
};
355+
356+
devShells = simpleDevShells // nixDevShells;
357+
358+
packages = allPackages // {
359+
# See https://github.com/NixOS/nix/issues/5591
360+
# nix flake cannot build a list/set of derivation in one command.
361+
# Using a linkFarmFromDrvs, I'm creating a unique entry point to
362+
# build all HLS versions.
363+
# This is used in CI to test and populate cache for packages
364+
# distributed using nix.
365+
all-haskell-language-server = linkFarmFromDrvs "all-haskell-language-server" (lib.unique (builtins.attrValues allPackages));
366+
367+
# Same for all shells
368+
# We try to build as much as possible, but not much shells are
369+
# working (especially on darwing), so this list is limited.
370+
all-nix-dev-shells = linkFarmFromDrvs "all-dev-shells" (builtins.map (shell: shell.inputDerivation) (lib.unique [nixDevShells.haskell-language-server-dev-nix]));
302371

303-
# docs
372+
all-simple-dev-shells = linkFarmFromDrvs "all-dev-shells" (builtins.map (shell: shell.inputDerivation) (lib.unique (builtins.attrValues simpleDevShells)));
304373
docs = docs;
305374
};
306375

307376
defaultPackage = packages.haskell-language-server;
308377

309-
devShell = packages.haskell-language-server-dev;
378+
devShell = devShells.haskell-language-server-dev;
310379
});
311380
}

0 commit comments

Comments
 (0)