Skip to content

Add flake support to hix #1572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 44 additions & 184 deletions docs/tutorials/getting-started-hix.md
Original file line number Diff line number Diff line change
@@ -1,227 +1,87 @@
# Getting started with Hix

The `hix` tools are wrappers for the various `nix` tools that
use `haskell.nix` without the need to add any `.nix` files.
Hix is a command line tool that provides an easy way to add haskell.nix
support to existing haskell projects.

This is useful for:
You will need `nix` installed and in you `PATH` with nix in PATH with
`experimental-features = [ "nix-command" "flakes" ];` configured.
See https://nixos.wiki/wiki/Flakes for details.

* A quick way to try out haskell.nix for new users.
## Using `hix init` and `nix`

* Using haskell.nix to work on projects that do not have
`.nix` files.
The `hix init` command adds a `flake.nix` and `nix/hix.nix` file.
After that the project can be used with regular `nix` tools.

* Testing to see if `haskell.nix` can build a project.
For instance to run `cabal build` on the `hello` package from hackage:

* Making `flake` and `non flake` configurations to check `haskell.nix`
treats them the same.

## Installing Nix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add a small n.b. to remind user that hix require having nix in PATH with experimental-features = [ "nix-command" "flakes" ]; enabled?


To use Hix you will need to install [Nix](https://nixos.org/download.html).

## Setting up the binary cache

IMPORTANT: you *must* do this or you *will* build several copies of GHC!

You can configure Nix to use our binary cache, which is pushed to by CI, so should contain the artifacts that you need.
```bash
cabal unpack hello
cd hello-1.0.0.2
nix run "github:input-output-hk/haskell.nix#hix" -- init
nix develop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All nix commands fail on my computer: error: getting status of '/nix/store/m5kk00h3yvjbyw4frcf00hzaigf0p7p0-source/hello-1.0.0.2': No such file or directory

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, hello-1.0.0.2 folder was in another flake subdirectory and I guess direnv mess a bit with dev shells … now I have this issue:

yvan@X230 ~/IOHK/hello-1.0.0.2 % nix develop
warning: Using saved setting for 'allow-import-from-derivation = true' from ~/.local/share/nix/trusted-settings.json.
warning: Using saved setting for 'extra-substituters = https://cache.iog.io' from ~/.local/share/nix/trusted-settings.json.
warning: Using saved setting for 'extra-trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=' from ~/.local/share/nix/trusted-settings.json.
error: The option `crossPlatforms' does not exist. Definition values:
       - In `<unknown-file>': <function>
(use '--show-trace' to show detailed location information)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full log with --show-trace:

error: The option `crossPlatforms' does not exist. Definition values:
       - In `<unknown-file>': <function>

       … while evaluating the attribute 'config'

       at /nix/store/l4ysisamwr0jdf6w2za4zygj9ajlf0wb-source/lib/modules.nix:357:9:

          356|         options = checked options;
          357|         config = checked (removeAttrs config [ "_module" ]);
             |         ^
          358|         _module = checked (config._module);

       … while evaluating 'hasSuffix'

       at /nix/store/l4ysisamwr0jdf6w2za4zygj9ajlf0wb-source/lib/strings.nix:235:5:

          234|     # Input string
          235|     content:
             |     ^
          236|     let

       … from call site

       at /nix/store/im0h1rigra4mw84y1ml8k2mr6ryjrpdc-source/overlays/haskell.nix:839:16:

          838|           in
          839|             if final.lib.hasSuffix ".yaml" selectedFileName
             |                ^
          840|               then stackProject' ([

       … while evaluating 'project''

       at /nix/store/im0h1rigra4mw84y1ml8k2mr6ryjrpdc-source/overlays/haskell.nix:811:20:

          810|         # used (as it will use a default `cabal.project`).
          811|         project' = projectModule:
             |                    ^
          812|           let

       … from call site

       at /nix/store/im0h1rigra4mw84y1ml8k2mr6ryjrpdc-source/overlays/haskell.nix:852:33:

          851|         # for `cabalPackage` and `stackPackage`.
          852|         project = args: let p = project' args;
             |                                 ^
          853|           in p.hsPkgs // p;

       … while evaluating 'project'

       at /nix/store/im0h1rigra4mw84y1ml8k2mr6ryjrpdc-source/overlays/haskell.nix:852:19:

          851|         # for `cabalPackage` and `stackPackage`.
          852|         project = args: let p = project' args;
             |                   ^
          853|           in p.hsPkgs // p;

       … from call site

       at /nix/store/im0h1rigra4mw84y1ml8k2mr6ryjrpdc-source/overlays/hix.nix:38:8:

           37|       projectDefaults = importDefaults (toString (src.origSrcSubDir or src) + "/nix/hix.nix");
           38|     in final.haskell-nix.project [
             |        ^
           39|             (import ../modules/hix-project.nix)

       … while evaluating 'project'

       at /nix/store/im0h1rigra4mw84y1ml8k2mr6ryjrpdc-source/overlays/hix.nix:3:5:

            2|   project =
            3|     { src
             |     ^
            4|     , userDefaults ? {}

       … from call site

       at /nix/store/07ym39kzdnn7h45zz6v78286d3vs1sax-source/flake.nix:19:15:

           18|             hixProject =
           19|               final.haskell-nix.hix.project {
             |               ^
           20|                 src = ./.;

       … while evaluating the attribute 'hixProject.flake'

       at /nix/store/07ym39kzdnn7h45zz6v78286d3vs1sax-source/flake.nix:18:13:

           17|           (final: prev: {
           18|             hixProject =
             |             ^
           19|               final.haskell-nix.hix.project {

       … while evaluating anonymous lambda

       at /nix/store/07ym39kzdnn7h45zz6v78286d3vs1sax-source/flake.nix:14:52:

           13|     in
           14|       flake-utils.lib.eachSystem supportedSystems (system:
             |                                                    ^
           15|       let

       … from call site

       at /nix/store/0zdncmv2n5sncs0sdphvggc61ix1fpsm-source/default.nix:128:17:

          127|         let
          128|           ret = f system;
             |                 ^
          129|           op = attrs: key:

       … while evaluating 'op'

       at /nix/store/0zdncmv2n5sncs0sdphvggc61ix1fpsm-source/default.nix:126:19:

          125|       # Merge together the outputs for all systems.
          126|       op = attrs: system:
             |                   ^
          127|         let

       … from call site

       at /nix/store/0zdncmv2n5sncs0sdphvggc61ix1fpsm-source/default.nix:144:5:

          143|     in
          144|     builtins.foldl' op { } systems
             |     ^
          145|   ;

       … while evaluating 'eachSystem'

       at /nix/store/0zdncmv2n5sncs0sdphvggc61ix1fpsm-source/default.nix:98:25:

           97|   #
           98|   eachSystem = systems: f:
             |                         ^
           99|     let

       … from call site

       at /nix/store/07ym39kzdnn7h45zz6v78286d3vs1sax-source/flake.nix:14:7:

           13|     in
           14|       flake-utils.lib.eachSystem supportedSystems (system:
             |       ^
           15|       let

       … while evaluating 'outputs'

       at /nix/store/07ym39kzdnn7h45zz6v78286d3vs1sax-source/flake.nix:5:13:

            4|   inputs.flake-utils.url = "github:numtide/flake-utils";
            5|   outputs = { self, nixpkgs, flake-utils, haskellNix }:
             |             ^
            6|     let

       … from call site

       at «string»:45:21:

           44|
           45|           outputs = flake.outputs (inputs // { self = result; });
             |                     ^
           46|

       … while evaluating anonymous lambda

       at «string»:10:13:

            9|     builtins.mapAttrs
           10|       (key: node:
             |             ^
           11|         let

       … from call site

       … while evaluating anonymous lambda

       at «string»:2:23:

            1|
            2| lockFileStr: rootSrc: rootSubdir:
             |                       ^
            3|

       … from call site

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to say when testing this you need to also pass something to point haskellNix to the PR branch. Something like:

nix develop --override-input haskellNix "github:input-output-hk/haskell.nix/hkm/hix-flake"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I confirm that everything works as expected :)

cabal build
```

You need to add the following sections to `/etc/nix/nix.conf` or, if you are a trusted user, `~/.config/nix/nix.conf` (if you don't know what a "trusted user" is, you probably want to do the former).
To view the contents of the flake run:

```
trusted-public-keys = [...] hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= [...]
substituters = [...] https://cache.iog.io [...]
nix flake show
```

If you're running NixOS, you need to add/update the following in your `/etc/nixos/configuration.nix` files instead.
To build a component with nix:

```
# Binary Cache for Haskell.nix
nix.settings.trusted-public-keys = [
"hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ="
];
nix.settings.substituters = [
"https://cache.iog.io"
];
nix build .#hello:exe:hello
```

NixOS-21.11 and older use slightly different settings.
To build and run a component:

```
# Binary Cache for Haskell.nix
nix.binaryCachePublicKeys = [
"hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ="
];
nix.binaryCaches = [
"https://cache.iog.io"
];
nix run .#hello:exe:hello
```

This can be tricky to get setup properly. If you're still having trouble getting cache hits, consult the corresponding [troubleshooting section](../troubleshooting.md#why-am-i-building-ghc).

## Installing Hix

To use the other Hix features first install Hix with:

```
nix-env -iA hix -f https://github.com/input-output-hk/haskell.nix/tarball/master
```

## Updating Hix (also updates hackage)
To update run to the latest version run:

```
hix update
```

This is also necessary to make the latest nightly snapshot of hackage
avaiable to nix.

## Building with Hix

To run `cabal build` in a nix-shell with all the dependencies required:

```
cabal unpack hello
cd hello-1.0.0.2
hix-shell --run 'cabal build'
```

Build with nix:

```
hix-build -A hsPkgs.hello.components.exes.hello
```

Cross compile to JavaScript:

```
hix-build -A projectCross.ghcjs.hsPkgs.hello.components.exes.hello
```

## Configuring Hix

The configuration arguments for `Hix` can be (from highest precedence to lowest):

* Passed on the command line with `--arg` (or `--argstr` for string args).

* Placed in `nix/hix.nix` file in the project dir.

* Placed in `~/.config/hix/hix.conf`

For example to build with GHC 8.10.7:

```
hix-shell --argstr compiler-nix-name ghc8107 --run 'cabal build'
```

or add a `nix/hix.nix` or `~/.config/hix/hix.conf` file:

```nix
{ compiler-nix-name = "ghc8107"; }
```

Here are just a few of the other configuration arguments you could use
in the files or on the command line (they are all optional):

```nix
{ name = "hello"; # for better error messages and derivation names
nixpkgsPin = "nixpkgs-unstable"; # or nixpkgs-2111 or nixpkgs-2105
nixpkgs = <nixpkgs>; # use this instead of nixpkgsPin
subDir = "some/sub/dir"; # sub dir containing the haskell project
projectFileName = "stack.yaml"; # use this project file
tools.haskell-language-server = "latest";
tools.hlint = "latest"; # Include the latest hls and hlint in the shell
index-state = "2021-02-22T00:00:00Z"; # It is normally best to put this in `cabal.project` (not here)

# PLUS MANY MORE! Almost any argument you can pass to the project functions
# or to `shellFor` can be used in as a Hix configuration argument.

}
```

## Adding Nix Support with Niv
## Using `hix develop`, `hix flake`, `hix build` and `hix run`

If you have a `nix/hix.nix` file with suitable configuration that
you want to make available to users with Nix (without having to
install Hix).
These commands work the same as the `nix` versions
without using the `flake.nix`. Instead a boiler
plate haskell.nix flake.nix file is added to
`.hix-flake/flake.nix` and used from there.

[Niv](https://github.com/nmattia/niv) is a command line tool for keeping track of Nix project dependencies.
The is can be useful if the project already includes a
`flake.nix` or if you do not intend to maintain one.

After installing niv you can initialize niv and pin the latest haskell.nix
commit by running the following in the root directory of the project:

```
niv init
niv add input-output-hk/haskell.nix -n haskellNix
```
Then all of these should work without the need to
run `hix init`:

Add `default.nix`:

```nix
(import (import nix/sources.nix).haskellNix {}).hix.project { src = ./.; }
```

If you want to also pin `nixpkgs` with Niv use:

```nix
let
sources = import nix/sources.nix;
in
(import sources.haskellNix {}).hix.project {
inherit (sources) nixpkgs;
src = ./.;
}
hix develop
hix flake show
hix build .#hello:exe:hello
hix run .#hello:exe:hello
```

Add `shell.nix`:
## Using `hix-shell` and `hix-build`

```nix
(import ./.).shell
```

When you want to update to the latest version of haskell.nix use:
These commands behave like `nix-build` and `hix-shell`
would if a boiler plate `default.nix` and `shell.nix`
we present.

```
niv update haskellNix
```

## Adding Nix Flake Support

To add flake support that uses the `nix/hix.nix` configuration in your
follow the [Getting started with flakes](getting-started.md) guide, but
use `haskell-nix.hix.project` instead of `haskell-nix.project'`

The `nixpkgs` used will need to be selected as a flake input (any selection
made in `nix/hix.nix` will be ignored).

Example `flake.nix` file:

```nix
{
description = "A very basic flake";
inputs.haskellNix.url = "github:input-output-hk/haskell.nix";
inputs.nixpkgs.follows = "haskellNix/nixpkgs-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, nixpkgs, flake-utils, haskellNix }:
flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" ] (system:
let
overlays = [ haskellNix.overlay
(final: prev: {
# This overlay adds our project to pkgs
helloProject =
final.haskell-nix.hix.project {
src = ./.;
# Other project options can be put in `nix/hix.nix`
};
})
];
pkgs = import nixpkgs { inherit system overlays; inherit (haskellNix) config; };
flake = pkgs.helloProject.flake {
# This adds support for `nix build .#js-unknown-ghcjs:hello:exe:hello`
crossPlatforms = p: [p.ghcjs];
};
in flake // {
# Built by `nix build .`
defaultPackage = flake.packages."hello:exe:hello";
});
}
hix-shell --run 'cabal build all'
hix-build -A hsPkgs.hello.components.exes.hello
```


2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@
# Exposed so that buildkite can check that `allow-import-from-derivation=false` works for core of haskell.nix
roots = legacyPackagesUnstable.haskell-nix.roots compiler;

packages = ((self.internal.compat { inherit system; }).hix).apps;

devShell = with self.legacyPackages.${system};
mkShell {
buildInputs = [
Expand Down
Loading