on c52845f help sign in
haskell.nix/docs/tutorials/cross-compilation.md
184 lines 5.9 kB history raw
1Cross compilation of Haskell projects involves building a version of
2GHC that outputs code for the target platform, and providing builds of
3all library dependencies for that platform.
5First, understand how to cross-compile a normal package from
6Nixpkgs. Matthew Bauer's [Beginners' guide to cross compilation in
7Nixpkgs][bauer] is a useful resource.
9[bauer]: https://matthewbauer.us/blog/beginners-guide-to-cross.html
12Using an example from the guide, this builds GNU Hello for a Raspberry
13Pi:
15 nix build -f '<nixpkgs>' pkgsCross.raspberryPi.hello
17We will use the same principle in [Haskell.nix][] — replacing the normal
18package set `pkgs` with a cross-compiling package set
19`pkgsCross.raspberryPi`.
21### Raspberry Pi example
23This is an example of using [Haskell.nix][] to build the [Bench][]
24command-line utility, which is a Haskell program.
26```nix
27{ pkgs ? import <nixpkgs> {} }:
28let
29 haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz);
30 native = haskellNix { inherit pkgs; };
31in
32 native.haskellPackages.bench.components.exes.bench
33```
35Now switch the package set as in the previous example:
37```nix
38{ pkgs ? import <nixpkgs> {} }:
39let
40 haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz);
41 raspberryPi = haskellNix { pkgs = pkgs.pkgsCross.raspberryPi; };
42in
43 raspberryPi.haskellPackages.bench.components.exes.bench
44```
46You should be prepared for a long wait because it first needs to build
47GHC, before building all the Haskell dependencies of [Bench][]. If all
48of these dependencies compiled successfully, I would be very surprised!
50!!! hint
51 The above example won't build, but you can try and see, if you like.
52 It will fail on [clock-0.7.2](http://hackage.haskell.org/package/clock-0.7.2),
53 which needs a patch to build.
55To fix the build problems, you must add extra configuration to the
56package set. Your project will have a [`mkStackPkgSet`](../reference/library.md#mkstackpkgset) or
57[`mkCabalProjectPkgSet`](../reference/library.md#mkcabalprojectpkgset). It is there where you must add
58[module options](../reference/modules.md) for setting compiler flags, adding patches, and so on.
60!!! note
61 Note that `haskell.nix` will automatically use `qemu` to emulate the target
62 when necessary to run Template Haskell splices.
64### Static executables with Musl libc
66Another application of cross-compiling is to produce fully static
67binaries for Linux. For information about how to do that with the
68[Nixpkgs Haskell infrastructure][nixpkgs] (not [Haskell.nix][]), see
69[nh2/static‑haskell‑nix][nh2]. Vaibhav Sagar's linked
70[blog post][vaibhav] is also very informative.
73```nix
74{ pkgs ? import <nixpkgs> {} }:
75let
76 haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz);
77 musl64 = haskellNix { pkgs = pkgs.pkgsCross.musl64; };
78in
79 musl64.haskellPackages.bench.components.exes.bench
80```
82This example will build [Bench][] linked against Musl libc. However
83the executable will still be dynamically linked. To get fully static
84executables you must add package overrides to:
861. Disable dynamic linking
872. Provide static versions of system libraries. (For more details, see
88 [Vaibhav's article][vaibhav]).
90```nix
92 packages.bench.components.exes.bench.configureFlags =
93 stdenv.lib.optionals stdenv.hostPlatform.isMusl [
94 "--disable-executable-dynamic"
95 "--disable-shared"
96 "--ghc-option=-optl=-pthread"
97 "--ghc-option=-optl=-static"
98 "--ghc-option=-optl=-L${gmp6.override { withStatic = true; }}/lib"
99 "--ghc-option=-optl=-L${zlib.static}/lib"
100 ];
102```
104!!! note "Licensing"
105 Note that if copyleft licensing your program is a problem for you,
106 then you need to statically link with `integer-simple` rather than
107 `integer-gmp`. However, at present, [Haskell.nix][] does not provide
108 an option for this.
111### How to cross-compile your project
113Set up your project Haskell package set.
115```nix
116# default.nix
117{ pkgs ? import <nixpkgs> {}
118let
119 # Import the Haskell.nix library,
120 haskell = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz) {
121 inherit pkgs;
122 };
124 # Instantiate a package set using the generated file.
125 pkgSet = haskell.mkCabalProjectPkgSet {
126 plan-pkgs = import ./pkgs.nix;
127 pkg-def-extras = [];
128 modules = [
129 {
130 # You will need to put build fixes here.
131 }
132 ];
133 };
134in
135 pkgSet.config.hsPkgs
136```
138Apply that package set to the Nixpkgs cross package sets that you are
139interested in.
141We are going to expand the `pkgs.pkgsCross` shortcut to be more
142explicit.
144```nix
145let
146 pkgs = import <nixpkgs> {}
147in {
148 shortcut = pkgs.pkgsCross.SYSTEM;
149 actual = import <nixpkgs> { crossSystem = pkgs.lib.systems.examples.SYSTEM; };
151```
153In the above example, for any `SYSTEM`, `shortcut` and `actual` are
154the same package set.
156```nix
157# release.nix
158let
159 myProject = import ./default.nix;
161 pkgsNative = import <nixpkgs> {};
162 pkgsRaspberryPi = import <nixpkgs> {
163 crossSystem = pkgsNative.lib.systems.examples.raspberryPi;
164 };
166 native = myProject { pkgs = pkgsNative; };
167 crossRaspberryPi = myProject { pkgs = pkgsRaspberryPi; };
169in {
170 my-project-native = native.my-project.components.exes.my-project;
171 my-project-raspberry-pi = crossRaspberryPi.my-project.components.exes.my-project;
173```
175Try to build it, and apply fixes to the `modules` list, until there
176are no errors left.
180[nh2]: https://github.com/nh2/static-haskell-nix
181[vaibhav]: https://vaibhavsagar.com/blog/2018/01/03/static-haskell-nix/
182[haskell.nix]: https://github.com/input-output-hk/haskell.nix
183[bench]: https://hackage.haskell.org/package/bench
184[nixpkgs]: https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure