Skip to content
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

Improve documentation on the structure of the survey file #117

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
57 changes: 40 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,6 @@ We have multiple CIs:
* Builds with latest nixpkgs `unstable`, daily: Shows up as **Scheduled build**.
May break when nixpkgs upstream changes.

## Building a minimal example (don't use this in practice)

`default.nix` builds an example executable (originally from https://github.com/vaibhavsagar/experiments). Run:

```
NIX_PATH=nixpkgs=nixpkgs nix-build --no-link
```

This prints a path that contains the fully linked static executable in the `bin` subdirectory.

This example is so that you get the general idea.
In practice, you probably want to use one of the approaches from the "Building arbitrary packages" or "Building stack projects" sections below.

## Binary caches for faster building (optional)

Install [cachix](https://static-haskell-nix.cachix.org/) and run `cachix use static-haskell-nix` before your `nix-build`.
Expand All @@ -99,20 +86,56 @@ Note that you may not get cached results if you use a different `nix` version th

## Building arbitrary packages

The [`survey`](./survey) directory maintains a select set of Haskell executables that are known and not known to work with this approach; contributions are welcome to grow the set of working executables.
Run for example:
The [`survey/default.nix`](./survey/default.nix) was originally a survey of Haskell executables that are known to (and known _not_ to) work with this approach, however it also exposes packages sets with overridden Haskell packages and dependencies that you can use to build _your own_ packages. The name `survey` shouldn't put you off from using it.

If you are a nix user, you can `import` this functionality and override the `haskellPackages` to include your own package, for example in the [PostgREST project](https://github.com/PostgREST/postgrest/blob/main/nix/static-haskell-package.nix).
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The PostgREST example is slightly complex, but I think it's probably better to include an (recent and maintained) example rather than not though?

Copy link
Owner

Choose a reason for hiding this comment

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

I think PostgREST ist fine but we should pin th link to a git commit (key Y in Github).


### Structure of `survey/default.nix`

The process of building up to the final `haskellPackages` is broken down into multiple steps, with the intermediate package sets also exposed for your use.
Copy link
Owner

Choose a reason for hiding this comment

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

steps -> [overlays](https://nixos.org/manual/nixpkgs/stable/#chap-overlays).


We start with a plain nixpkgs named `normalPkgs`, defaulting to the version provided by [`nixpkgs.nix`](./nixpkgs.nix), but you can pass in your own version here.
You could instead provide `overlays`, which get applied to `normalPkgs`.
The `.pkgsMusl` from `normalPkgs` now forms our base `pkgs`.

Copy link
Owner

Choose a reason for hiding this comment

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

I propose to format the below as a list of the overlays and exposed package sets, and then for each explain its goal as you do, e.g. with this structure:

* `archiveFilesOverlay`
  * exposed package set: `archiveFilesOverlay`
  * **Goal:** Packages in `pkgsMusl` typically [..]
* `haskellLibsReadyForStaticLinkingOverlay`
  * exposed package set: `pkgsWithHaskellLibsReadyForStaticLinking`
* `staticHaskellBinariesOverlay`
  * ...
* `pkgsWithStaticHaskellBinaries`
  * ...

Packages in `pkgsMusl` typically [only include `.so` files](https://github.com/NixOS/nixpkgs/issues/61575), but not `.a` files. We create a `archiveFilesOverlay`, which overrides our Haskell dependencies (i.e. C libraries) to include `.a` files as well.
This usually involves low-level library specific actions, but the goal is to upstream these to nixpkgs under a `dontDisableStatic` attribute.
We apply this overlay to `pkgs` to get `pkgsWithArchiveFiles`.

This package set _may_ be sufficient for your needs if you have a separate build system (e.g. Bazel) and are only after a statically linked GHC and library dependencies.
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'm not sure if this is actually true for GHC >= 9.6 as we now have the fixGhc step that only gets applied in pkgsWithStaticHaskellBinaries (to deal with DWARF and Hadrian).

The Skyscope example that uses pkgsWithArchiveFiles I believe is only using GHC 9.0.2, so isn't affected.
https://github.com/tweag/skyscope/pull/94/files#diff-8cce62c1be86c722f621f909a18b4a5df8eef70b6399b40194894ad9ce09f0abR20

Do you remember if there was a reason why the fixGhc was not applied earlier? (I intend to try moving it earlier and seeing if the derivation changes/anything breaks).

Copy link
Owner

Choose a reason for hiding this comment

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

Do you remember if there was a reason why the fixGhc was not applied earlier? (I intend to try moving it earlier and seeing if the derivation changes/anything breaks).

It look like moving it earlier should work fine and makes sense.

Copy link
Collaborator Author

@jonathanlking jonathanlking Jul 31, 2023

Choose a reason for hiding this comment

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

Great, I intend to leave this white lie (for now) in the documentation and we can have a separate PR to move the fixGhc step earlier up.

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've just noticed that at the moment pkgsWithArchiveFiles is slightly more broken than I realised.
I think the compiler override only gets applied in the haskellLibsReadyForStaticLinkingOverlay.

nix-repl> pkgs = import ./survey/default.nix { compiler = "ghc962"; }

nix-repl> pkgs.pkgsWithArchiveFiles.ghc
«derivation /nix/store/pd3h7k2f9p9290dhfch2wnwkp9714xgk-ghc-musl-9.2.7.drv»

nix-repl> pkgs.haskellPackagesWithLibsReadyForStaticLinking.ghc
«derivation /nix/store/11rnlr5qbk1pxwk4zjyb3xyz8wz2fyx6-ghc-musl-9.6.2.drv»

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've had a go at moving GHC earlier here #118.


The next step is to configure Hackage library packages to use static linking. This is done by the `haskellLibsReadyForStaticLinkingOverlay` to produce `pkgsWithHaskellLibsReadyForStaticLinking`.
TODO: Document what `addStaticLinkerFlagsWithPkgconfig` does.

Finally `staticHaskellBinariesOverlay` infers which haskell packages are binaries, and overrides them using the `statify` function, which primarily sets the `--enable-executable-static` Cabal flag.
This produces `pkgsWithStaticHaskellBinaries`, which is where the `haskellPackages` attribute set is taken from.

### Building existing packages in the survey

To build existing packages, run:

```
NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix -A working
```

There are multiple package sets available in the survey (select via `-A`):
Relevant package sets available in the survey include (select via `-A`):

* `working` -- build all exes known to be working
* `notWorking` -- build all exes known to be not working (help welcome to make them work)
* `haskellPackages.somePackage` -- build a specific package from our overridden package set

If you are a nix user, you can easily `import` this functionality and add an override to add your own packages.
## Building a minimal example (don't use this in practice)

`default.nix` builds an example executable (originally from https://github.com/vaibhavsagar/experiments). Run:

```
NIX_PATH=nixpkgs=nixpkgs nix-build --no-link
```

This prints a path that contains the fully linked static executable in the `bin` subdirectory.

This example is so that you get the general idea.
In practice, you probably want to use one of the approaches from the "Building arbitrary packages" or "Building stack projects" sections below.
Copy link
Owner

Choose a reason for hiding this comment

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

I would probably still keep that at the top, so that the user gets a rough idea of what's happening by looking at a short file which isn't thousands of lines long (we might state that even more explicitly, and remove the probably).

If we do move it down, then sections below needs to be updated.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ok, that's fair — my motivation was that we should tell readers how to do something first, before telling them how not to do it.

I think we should replace the minimal example entirely with instructions on how to use the survey, perhaps like
#88 (comment), but this is out of scope of this PR and can be discussed later.


## Building `stack` projects

Expand Down