nh2 / static-haskell-nix

easily build most Haskell programs into fully static Linux executables
388 stars 36 forks source link

How do I actually use this? #88

Open athas opened 4 years ago

athas commented 4 years ago

I have a Haskell program that I would like to build statically with Nix. I currently link with glibc, which has the usual problems, so I'm quite interested in linking with Musl instead. But while I use Nix and NixOS, I'm afraid I don't quite understand the instructions here. The only clear example I can find of how to link my own, single package against musl is the minimal example, which I am told not to use in practice. Apart from that, the documentation points me at survey/default.nix, which is a 1300 line .nix file, and encourages me to "easily import this functionality and add an override to add your own packages". I've tried reading the code, but I'm afraid I have no idea what is going on, or how to make use of it.

Is there a simple example of how to use this somewhere?

nh2 commented 4 years ago

Hey @athas, given that futhark is already in nixpkgs, the simplest approach would be to clone this repo (including nixpkgs submodule) and run:

Approach 1: Using futhark already in nixpkgs

NIX_PATH=. nix-build --no-link survey/default.nix -A haskellPackages.futhark

That'd build futhark as is in nixpkgs, with all the overrides for various system and Haskell packages to make static linking work.

You can also add --arg disableOptimization true to make building faster, and use the cachix from the README to speed it up.

This gets pretty far, until:

  Setup: Encountered missing dependencies:
  base >=4.13 && <5, containers >=0.6.2.1, megaparsec >=8.0.0

If you wanted to lift that restriction to check if it'd work without the bounds, you could add futhark = doJailbreak super.futhark; into survey/default.nix, next to where such a jailbreak is done for erd. However, the bounds are justified because the containers in the pinned nixpkgs does not have the version you need yet:

src/Futhark/Representation/AST/Attributes/Names.hs:82:32: error:
    Not in scope: ‘IM.disjoint’
    Module ‘Data.IntMap.Strict’ does not export ‘disjoint’.
   |
82 | namesIntersect vs1 vs2 = not $ IM.disjoint (unNames vs1) (unNames vs2)
   |                                ^^^^^^^^^^^

Approach 2: Providing your own nixpkgs

Instead of using the pinned nixpkgs, you can provide your own. Check out the logic in nixpkgs.nix for that. You can delete the submodule and update the URL in fetchTarball given there, or simply check out the version you want inside the nixpkgs submodule.

You can also import static-haskell-nix, and provide it with a normalPkgs updated according to your wishes. An example of that is shown e.g. in https://github.com/nh2/static-haskell-nix/issues/73#issue-549316223.

Do take into account though that current nixpkgs nixos-unstable had a recent breakage in that the GNU gold linker was enabled but could not link musl binaries (https://github.com/NixOS/nixpkgs/pull/84741). That was likely addressed Friday in nixpkgs master, but Hydra has not built it and advanced nixos-unstable yet. Also, the switch in nixpkgs to GHC 8.8 is very recent, and my CI hasn't built it yet (have to wait for the previous fix to land in unstable). Thus, I recommend to start with a version of Futhark that works on 8.6.5 with my pinned nixpkgs first.

Approach 3: stack2nix

Given that Futhark also has a stack project, you can follow the Building stack projects section.

Here too though, start with a Stackage snapshot that uses GHC 8.6.5, for the same reason as above.


I hope this helps getting you forward. I'm also happy to help getting Futhark build statically. When we've figured it out, let's discuss which of these approaches should have more presence in the README and what should be written there!

athas commented 4 years ago

Thanks for the advice. I suspect some of my own explorations ran into the upstream musl/gold problem. It can be a bit hard to tell what's a persistent error and what's just temporary breakage. I will try to go with Approach 2, because I am interested in doing builds independently of the Futhark in nixpkgs (which can be arbitrarily out of date, and is certainly not usable for producing nightly builds in CI).

nh2 commented 4 years ago

@athas Yes, that makes sense; approach 2 is also what Dhall uses.

It can be a bit hard to tell what's a persistent error and what's just temporary breakage.

The CI may help with it; consider for example https://buildkite.com/nh2/static-haskell-nix/builds?branch=master&page=2

image

It shows that on master with my pinned nixpkgs everything builds as expected, but the Scheduled build (nightly against current nixpkgs nixos-unstable) fails every night.

Unfortunately it doesn't allow me to show these things in separate lists, or as separate badges; both are master for Buildkite.

mikelpr commented 4 years ago

is there a way of using it directly from a .nix without cloning the repo? via e.g. builtins.fetchGit

monacoremo commented 4 years ago

is there a way of using it directly from a .nix without cloning the repo? via e.g. builtins.fetchGit

@mikelpr we have an example here: https://github.com/PostgREST/postgrest/blob/master/nix/static-haskell-package.nix

expipiplus1 commented 3 years ago

It would be great to add the information in this issue to the readme, especially a link to, or condensed version of @monacoremo's expression ( https://github.com/PostgREST/postgrest/blob/master/nix/static-haskell-package.nix)

teto commented 3 years ago

yes that's a fantastic project ! The last green CI was october 6th, there seems to be a long backlog of pipelines that could probably be skipped. I would be interested in a nixpkgs bump to select ghc884 .

nh2 commented 3 years ago

The last green CI was october 6th, there seems to be a long backlog of pipelines that could probably be skipped.

Ah thanks, indeed an update seems to have sent the buildkite daemon into a crashloop due to permissions (probably because dir names changed due to https://github.com/NixOS/nixpkgs/pull/78373 and so the permissions were wrong).

I've fixed it now and cancelled the in-between unstable builds.

gleachkr commented 1 year ago

Here's a minimal flake for building a static binary. I've used this successfully to build a Yesod server, so it seems to work OK with template Haskell.

{
  description = "A Simple Static Haskell Binary";

  inputs = {
    nixpkgs = {
      url = "https://github.com/nh2/nixpkgs/archive/9e49f8f1f37bc906cda1adb33064c325d760819a.tar.gz";
      type = "tarball";
      flake = false;
    };
    static-haskell-nix = {
      url = "github:nh2/static-haskell-nix";
      flake = false;
    };
  };

  outputs = { self, nixpkgs, static-haskell-nix} :
    let
      compiler = "ghc927";
      name = "my-haskell-package";
      system = "x86_64-linux";
      overlay = self: super: {
        haskell = super.haskell // {
          packages = super.haskell.packages // {
            ${compiler} = super.haskell.packages.${compiler}.override {
              overrides = final: prev: {${name} = prev.callCabal2nix name ./. { };};
            };
          };
        };
      };
      overlays = [overlay];
      normalPkgs = import nixpkgs {inherit overlays system; };
      survey = import "${static-haskell-nix}/survey" { inherit compiler normalPkgs; };
    in
      {
        packages.${system}.default = survey.haskellPackages.${name};
      };
}

If anyone has any ideas for improvements, I'd love to hear them.

@nh2, would you consider a PR adding a templates flake?