Skip to content

Commit 5ebce0e

Browse files
authored
Make it easier to access executable components (#565)
This overlay helps accessing common executable components. Typically we want to make these available in a nix-shell created with shellFor. In most cases the package name will be the same as the executable, but we have a `toolPackageName` mapping to help when it is not. ``` # To get a single tool: haskell-nix.tool "cabal" "3.2.0.0" # This does the same thing as: (haskell-nix.hackage-package { name = "cabal-install" version = "3.2.0.0" }).components.exes.cabal # To get an attr set containing multiple tools: haskell-nix.tools { cabal = "3.2.0.0"; hlint = "2.2.11"; } # To add tools to a shell: shellFor { tools = { cabal = "3.2.0.0"; hlint = "2.2.11"; }; } ``` When used in shellFor the tools will be compiled with the same version of ghc used in the shell (the build ghc in the case of cross compilation). Instead of a version string we can use an attr set containing arguments that will be passed to `cabalProject`. For instance to specify the ghc used to compile. Use: ``` haskell-nix.tool "cabal" { version = "3.2.0.0"; ghc = haskell-nix.compiler.ghc883; } ```
1 parent 52401d7 commit 5ebce0e

File tree

9 files changed

+144
-9
lines changed

9 files changed

+144
-9
lines changed

build.nix

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ let
1616
in rec {
1717
tests = import ./test/default.nix { inherit pkgs ifdLevel; };
1818

19+
tools = pkgs.recurseIntoAttrs
20+
(pkgs.lib.mapAttrs (_: ghc:
21+
let
22+
tool = name: version: pkgs.buildPackages.haskell-nix.tool name { inherit version ghc; };
23+
in pkgs.recurseIntoAttrs {
24+
cabal-32 = tool "cabal" "3.2.0.0";
25+
ghcide = tool "ghcide" "object-code";
26+
} // pkgs.lib.optionalAttrs (ghc.version == "8.6.5") {
27+
cabal-30 = tool "cabal" "3.0.0.0";
28+
}) { inherit (pkgs.buildPackages.haskell-nix.compiler) ghc865 ghc883; });
29+
1930
# Scripts for keeping Hackage and Stackage up to date, and CI tasks.
2031
# The dontRecurseIntoAttrs prevents these from building on hydra
2132
# as not all of them can work in restricted eval mode (as they

builder/default.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ let
5151

5252
# Same as haskellPackages.shellFor in nixpkgs.
5353
shellFor = haskellLib.weakCallPackage pkgs ./shell-for.nix {
54-
inherit hsPkgs ghcForComponent makeConfigFiles hoogleLocal haskellLib;
54+
inherit hsPkgs ghcForComponent makeConfigFiles hoogleLocal haskellLib buildPackages;
5555
inherit (buildPackages) glibcLocales;
56+
buildGHC = ghc.passthru.buildGHC or ghc;
5657
};
5758

5859
# Same as haskellPackages.ghcWithPackages and ghcWithHoogle in nixpkgs.

builder/shell-for.nix

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{ lib, stdenv, glibcLocales, pkgconfig, ghcForComponent, makeConfigFiles, hsPkgs, hoogleLocal, haskellLib }:
1+
{ lib, stdenv, glibcLocales, pkgconfig, ghcForComponent, makeConfigFiles, hsPkgs, hoogleLocal, haskellLib, buildPackages, buildGHC }:
22

33
{ packages ? ps:
44
let
@@ -9,6 +9,7 @@
99
, additional ? _: []
1010
, withHoogle ? true
1111
, exactDeps ? false
12+
, tools ? {}
1213
, ... } @ args:
1314

1415
let
@@ -74,7 +75,7 @@ let
7475
# inherit (hsPkgs) hoogle;
7576
};
7677

77-
mkDrvArgs = builtins.removeAttrs args ["packages" "additional" "withHoogle"];
78+
mkDrvArgs = builtins.removeAttrs args ["packages" "additional" "withHoogle" "tools"];
7879
in
7980
stdenv.mkDerivation (mkDrvArgs // {
8081
name = mkDrvArgs.name or name;
@@ -84,7 +85,8 @@ in
8485
++ lib.optional withHoogle' hoogleIndex;
8586
nativeBuildInputs = [ ghcEnv ]
8687
++ nativeBuildInputs
87-
++ mkDrvArgs.nativeBuildInputs or [];
88+
++ mkDrvArgs.nativeBuildInputs or []
89+
++ lib.attrValues (buildPackages.haskell-nix.toolsForGhc buildGHC tools);
8890
phases = ["installPhase"];
8991
installPhase = "echo $nativeBuildInputs $buildInputs > $out";
9092
LANG = "en_US.UTF-8";

ci.nix

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ dimension "Nixpkgs version" nixpkgsVersions (nixpkgsName: nixpkgs-pin:
4141
# Native builds
4242
# TODO: can we merge this into the general case by picking an appropriate "cross system" to mean native?
4343
native = pkgs.recurseIntoAttrs {
44-
inherit (build) tests maintainer-scripts maintainer-script-cache;
44+
inherit (build) tests tools maintainer-scripts maintainer-script-cache;
4545
hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2"; }).components.exes.hello;
4646
iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
4747
ghc = pkgs.recurseIntoAttrs pkgs.haskell-nix.compiler;
@@ -53,6 +53,8 @@ dimension "Nixpkgs version" nixpkgsVersions (nixpkgsName: nixpkgs-pin:
5353
let pkgs = import pinnedNixpkgsSrc (nixpkgsArgs // { inherit system crossSystem; });
5454
build = import ./build.nix { inherit pkgs ifdLevel; };
5555
in pkgs.recurseIntoAttrs {
56+
# TODO: look into making tools work when cross compiling
57+
# inherit (build) tools;
5658
hello = (pkgs.haskell-nix.hackage-package { name = "hello"; version = "1.0.0.2"; }).components.exes.hello;
5759
iserv-proxy = pkgs.ghc-extra-packages.ghc865.iserv-proxy.components.exes.iserv-proxy;
5860
remote-iserv = pkgs.ghc-extra-packages.ghc865.remote-iserv.components.exes.remote-iserv;

docs/reference/library.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,11 @@ shellFor =
366366
| Argument | Type | Description |
367367
|----------------|------|---------------------|
368368
| `packages` | Function | Package selection function. It takes a list of [Haskell packages](#haskell-package) and returns a subset of these packages. |
369-
| `withHoogle` | Boolean | Whether to build a Hoogle documentation index and provide the `hoogle` command. |
370-
| `exactDeps` | Boolean | Prevents the Cabal solver from choosing any package dependency other than what are in the package set. |
371-
| `{ ... }` | Attrset | All the other arguments are passed to [`mkDerivation`](https://nixos.org/nixpkgs/manual/#sec-using-stdenv). |
369+
| `additional` | Function | Similar to `packages`, but the selected packages are built and included in `ghc-pkg list` (not just their dependencies). |
370+
| `withHoogle` | Boolean | Whether to build a Hoogle documentation index and provide the `hoogle` command. |
371+
| `exactDeps` | Boolean | Prevents the Cabal solver from choosing any package dependency other than what are in the package set. |
372+
| `tools` | Function | AttrSet of tools to make available e.g. `{ cabal = "3.2.0.0"; }` or `{ cabal = { version = "3.2.0.0"; }; }` |
373+
| `{ ... }` | Attrset | All the other arguments are passed to [`mkDerivation`](https://nixos.org/nixpkgs/manual/#sec-using-stdenv). |
372374

373375
**Return value**: a derivation
374376

docs/user-guide/development.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,14 @@ in
6666
withHoogle = true;
6767
6868
# You might want some extra tools in the shell (optional).
69+
70+
# Some common tools can be added with the `tools` argument
71+
tools = { cabal = "3.2.0.0"; hlint = "2.2.11"; };
72+
# See overlays/tools.nix for more details
73+
74+
# Some you may need to get some other way.
6975
buildInputs = with pkgs.haskellPackages;
70-
[ hlint stylish-haskell ghcid ];
76+
[ ghcid ];
7177
7278
# Prevents cabal from choosing alternate plans, so that
7379
# *all* dependencies are provided by Nix.

lib/default.nix

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,12 @@ with haskellLib;
199199
# This is the same as isCrossHost but for use when building ghc itself
200200
isCrossTarget = stdenv.targetPlatform != stdenv.hostPlatform
201201
&& !(stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl);
202+
203+
# Takes a version number or attr set of arguments (for cabalProject)
204+
# and conversios it to an attr set of argments. This allows
205+
# the use of "1.0.0.0" or { version = "1.0.0.0"; ... }
206+
versionOrArgsToArgs = versionOrArgs:
207+
if lib.isAttrs versionOrArgs
208+
then versionOrArgs
209+
else { version = versionOrArgs; };
202210
}

overlays/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
(import ./windows.nix)
1414
(import ./armv6l-linux.nix)
1515
(import ./musl.nix)
16+
(import ./tools.nix)
1617
# Restore nixpkgs haskell and haskellPackages
1718
(_: super: { inherit (super.haskell-nix-super) haskell haskellPackages; })
1819
]

overlays/tools.nix

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# This overlay helps accessing common executable components.
2+
# Typically we want to make these available in a nix-shell
3+
# created with shellFor. In most cases the package name
4+
# will be the same as the executable, but we have a
5+
# `toolPackageName` mapping to help when it is not.
6+
#
7+
# To get a single tool:
8+
# haskell-nix.tool "cabal" "3.2.0.0"
9+
#
10+
# This does the same thing as:
11+
# (haskell-nix.hackage-package {
12+
# name = "cabal-install"
13+
# version = "3.2.0.0"
14+
# }).components.exes.cabal
15+
#
16+
# To get an attr set containing multiple tools:
17+
# haskell-nix.tools { cabal = "3.2.0.0"; hlint = "2.2.11"; }
18+
#
19+
# To add tools to a shell:
20+
# shellFor { tools = { cabal = "3.2.0.0"; hlint = "2.2.11"; }; }
21+
#
22+
# When used in shellFor the tools will be compiled with the same version
23+
# of ghc used in the shell (the build ghc in the case of cross compilation).
24+
#
25+
# Instead of a version string we can use an attr set containing
26+
# arguments that will be passed to `cabalProject`.
27+
#
28+
# For instance to specify the ghc used to compile. Use:
29+
# haskell-nix.tool "cabal" {
30+
# version = "3.2.0.0";
31+
# ghc = haskell-nix.compiler.ghc883;
32+
# }
33+
#
34+
self: super:
35+
let
36+
inherit (self) lib;
37+
38+
in { haskell-nix = super.haskell-nix // {
39+
40+
# Some times the package name in hackage is not the same as tool name.
41+
toolPackageName = {
42+
cabal = "cabal-install";
43+
};
44+
45+
hackage-tool = { name, ... }@args:
46+
(self.haskell-nix.hackage-package
47+
(args // { name = self.haskell-nix.toolPackageName."${name}" or name; }))
48+
.components.exes."${name}";
49+
50+
tool = name: versionOrArgs:
51+
let
52+
args = self.haskell-nix.haskellLib.versionOrArgsToArgs versionOrArgs;
53+
in
54+
(if self.haskell-nix.custom-tools ? "${name}"
55+
&& self.haskell-nix.custom-tools."${name}" ? "${args.version}"
56+
then self.haskell-nix.custom-tools."${name}"."${args.version}"
57+
else self.haskell-nix.hackage-tool) (args // { inherit name; });
58+
59+
tools = lib.mapAttrs self.haskell-nix.tool;
60+
61+
# Like `tools` but allows default ghc to be specified
62+
toolsForGhc = ghc: toolSet:
63+
self.haskell-nix.tools (
64+
lib.mapAttrs (name: versionOrArgs:
65+
# Add default ghc if not specified in the args
66+
{ inherit ghc; }
67+
// self.haskell-nix.haskellLib.versionOrArgsToArgs versionOrArgs
68+
) toolSet
69+
);
70+
71+
# Tools not in hackage yet
72+
custom-tools = {
73+
ghcide.object-code = args:
74+
(self.haskell-nix.cabalProject (args // {
75+
name = "ghcide";
76+
src = self.fetchFromGitHub {
77+
owner = "mpickering";
78+
repo = "ghcide";
79+
rev = "706c59c97c25c66798815c1dc3ee6885a298918a";
80+
sha256 = "0d158xifwvz0y69ah98ckxakzqpz229mq7rpf2bpbmwhnpw3jmm6";
81+
};
82+
modules = [({config, ...}: {
83+
packages.ghcide.configureFlags = [ "--enable-executable-dynamic" ];
84+
nonReinstallablePkgs = [ "Cabal" "array" "base" "binary" "bytestring" "containers" "deepseq"
85+
"directory" "filepath" "ghc" "ghc-boot" "ghc-boot-th" "ghc-compact"
86+
"ghc-heap" "ghc-prim" "ghci" "haskeline" "hpc" "integer-gmp"
87+
"libiserv" "mtl" "parsec" "pretty" "process" "rts" "stm"
88+
"template-haskell" "terminfo" "text" "time" "transformers" "unix"
89+
"xhtml"
90+
];
91+
})];
92+
pkg-def-extras = [
93+
(hackage: {
94+
packages = {
95+
"alex" = (((hackage.alex)."3.2.5").revisions).default;
96+
"happy" = (((hackage.happy)."1.19.12").revisions).default;
97+
};
98+
})
99+
];
100+
})).ghcide.components.exes.ghcide;
101+
};
102+
}; }

0 commit comments

Comments
 (0)