Files
haskell.nix/docs/tutorials/cross-compilation.md

4.9 KiB
Raw Permalink Blame History

Cross compilation

Cross compilation of Haskell projects involves building a version of GHC that outputs code for the target platform, and providing builds of all library dependencies for that platform.

First, understand how to cross-compile a normal package from Nixpkgs. Matthew Bauer's Beginners' guide to cross compilation in Nixpkgs is a useful resource.

Using an example from the guide, this builds GNU Hello for a Raspberry Pi:

nix build -f '<nixpkgs>' pkgsCross.raspberryPi.hello

We will use the same principle in Haskell.nix — replacing the normal package set pkgs with a cross-compiling package set pkgsCross.raspberryPi.

Raspberry Pi example

This is an example of using Haskell.nix to build the Bench command-line utility, which is a Haskell program.

{ pkgs ? import <nixpkgs> {} }:
let
  haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz);
  native = haskellNix { inherit pkgs; };
in
  native.haskellPackages.bench.components.exes.bench

Now switch the package set as in the previous example:

{ pkgs ? import <nixpkgs> {} }:
let
  haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz);
  raspberryPi = haskellNix { pkgs = pkgs.pkgsCross.raspberryPi; };
in
  raspberryPi.haskellPackages.bench.components.exes.bench

You should be prepared for a long wait because it first needs to build GHC, before building all the Haskell dependencies of Bench. If all of these dependencies compiled successfully, I would be very surprised!

Hint:

The above example won't build, but you can try and see, if you like. It will fail on clock-0.7.2, which needs a patch to build.

To fix the build problems, you must add extra configuration to the package set. Your project will have a mkStackPkgSet or mkCabalProjectPkgSet. It is there where you must add module options for setting compiler flags, adding patches, and so on.

Note:

Note that haskell.nix will automatically use qemu to emulate the target when necessary to run Template Haskell splices.

Static executables with Musl libc

Another application of cross-compiling is to produce fully static binaries for Linux. For information about how to do that with the Nixpkgs Haskell infrastructure (not Haskell.nix), see nh2/statichaskellnix. Vaibhav Sagar's linked blog post is also very informative.

{ pkgs ? import <nixpkgs> {} }:
let
  haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz);
  musl64 = haskellNix { pkgs = pkgs.pkgsCross.musl64; };
in
  musl64.haskellPackages.bench.components.exes.bench

This example will build Bench linked against Musl libc. However the executable will still be dynamically linked. To get fully static executables you must add package overrides to:

  1. Disable dynamic linking
  2. Provide static versions of system libraries. (For more details, see Vaibhav's article).
{
  packages.bench.components.exes.bench.configureFlags =
    lib.optionals stdenv.hostPlatform.isMusl [
      "--disable-executable-dynamic"
      "--disable-shared"
      "--ghc-option=-optl=-pthread"
      "--ghc-option=-optl=-static"
      "--ghc-option=-optl=-L${gmp6.override { withStatic = true; }}/lib"
      "--ghc-option=-optl=-L${zlib.static}/lib"
    ];
}

Note: Licensing

Note that if copyleft licensing your program is a problem for you, then you need to statically link with integer-simple rather than integer-gmp. However, at present, Haskell.nix does not provide an option for this.

How to cross-compile your project

Set up your project Haskell package set.

{{#include cross-compilation/default.nix}}

Apply that package set to the Nixpkgs cross package sets that you are interested in.

We are going to expand the pkgs.pkgsCross shortcut to be more explicit.

let
  pkgs = import <nixpkgs> {}
in {
  shortcut = pkgs.pkgsCross.SYSTEM;
  actual = import <nixpkgs> { crossSystem = pkgs.lib.systems.examples.SYSTEM; };
}

In the above example, for any SYSTEM, shortcut and actual are the same package set.

{{#include cross-compilation/release.nix}}

Try to build it, and apply fixes to the modules list, until there are no errors left.