Skip to content
This repository has been archived by the owner on Mar 10, 2020. It is now read-only.

Building HaLVMs with Nix

David Johnson edited this page Apr 30, 2017 · 3 revisions

An optional approach to building HaLVM's is with the Nix package manager.

Table of Contents

  1. Motivation
  2. What is Nix
  3. HaLVM on Nixpkgs
  4. Building HaLVMs
    1. Obtaining Nix
    2. Nix-shell
    3. Hello World
    4. Compiling
  5. Advanced
    1. Cabal2Nix
  6. Additional Resources

Motivation

When building complex projects (i.e. with multiple GHCs) it is often desirable to have a build tool that can abstract over different compilers / language ecosystems. Nix is one such tool.

What is Nix

Nix is both a language and a package manager that was designed with the intent of building packages in a reproducible way.

Nix is a pure, dynamically-typed functional programming language that consists of expression evaluation and derivation building.

A derivation is an attribute set (set of key-value pairs) that when evaluated, produce build artifacts. All derivations are evaluated through the following script.

For more information on what a derivation is, please consult the following link. For more information on Nix, the package manager itself, please consult the following link.

HaLVM on Nixpkgs

The HaLVM has been given its own derivation on the official nixpkgs repository. This derivation can be used to build unikernels that run on the Xen hypervisor.

Nixpkgs is a collection of thousands of ready-made derivations that can be evaluated to build packages for a large number of language ecosystems (including Haskell packages).

Most packages on nixpkgs are available from a binary cache, and will be fetched as opposed to built, HaLVM-2.4.0 included.

For more information about and/or contributing to nixpkgs please consult the following link.

Building

HaLVM 2.4.0 is available for download via the Nix package manager in two flavors.

  • haskell.compiler.integer-simple.ghcHaLVM240
  • haskell.compiler.ghcHaLVM240 (The default integer-gmp build)

Nix does not use stack nor cabal-install to build Haskell projects. It builds, configures and installs Haskell packages into the /nix/store using GHC, a Setup.hs script, the Cabal library and a carefully populated GHC package database.

For more information on this process, please consult the following link.

Obtaining Nix

$ curl https://nixos.org/nix/install | sh

The contents of this script can be found here. It is recommended to read this before installing.

Nix-shell

The nix-shell command allows one to enter into an isolated shell environment with a package from the /nix/store available on the user's PATH, and other environment variables properly set.

nix-shell -p haskell.compiler.integer-simple.ghcHaLVM240

The above command will retrieve a pre-built binary of HaLVM-2.4.0 into /nix/store, bypassing building. It will then place the user into a shell with the HaLVM bin directory on the user's PATH. For more information about nix-shell, please consult the following link.

Hello World

Inside of the nix-shell we can now construct a simple unikernel that prints to the Xen console.

λ nixos ~  cat > Main.hs <<EOF
heredoc> module Main where
heredoc>
heredoc> import Hypervisor.Console
heredoc> import Control.Concurrent
heredoc> import Control.Monad
heredoc>
heredoc> main :: IO ()
heredoc> main = do
heredoc>   () <$ initXenConsole
heredoc>   forever $ do
heredoc>     threadDelay (1000 * 1000)
heredoc>     putStrLn "Hello world!"
heredoc> EOF

Compiling

We can now compile the above unikernel in our shell enviroment.

$ halvm-ghc Main.hs -o main

Exiting the shell will leave our unikernel in the same directory.

Advanced

Nix derivations can be generated from cabal files. This is useful for building Haskell projects with Nix.

Cabal2Nix

cabal2Nix is a simple command line utility for generating Nix files from a cabal file. Given our simple Hello World application above, we can provide a HelloWorld.cabal that looks like the following:

name:                HelloWorld
version:             0.1.0.0
author:              User
maintainer:          [email protected]
build-type:          Simple
extra-source-files:  ChangeLog.md
cabal-version:       >=1.10
executable HelloWorld
  main-is:             Main.hs
  build-depends:       base >=4.9 && <5
  default-language:    Haskell2010   

We can construct the HelloWorld.nix file with the following command:

cabal2nix . > HelloWorld.nix

Result:

{ mkDerivation, base, stdenv }:
mkDerivation {
  pname = "HelloWorld";
  version = "0.1.0.0";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [ base ];
  license = stdenv.lib.licenses.bsd3;
}

In order to evaluate the above derivation we must pass it in as an argument to callPackage, and then call nix-build.

$ cat > default.nix
{ pkgs ? import <nixpkgs> {} }:
 pkgs.haskell.packages.integer-simple.ghcHaLVM240.callPackage ./HelloWorld.nix {}

Calling nix-build will build our Haskell project, store the resulting unikernel in the /nix/store and place a symlink named result in the current working directory.

$ nix-build
...........
Building HelloWorld-0.1.0.0...
Preprocessing executable 'HelloWorld' for HelloWorld-0.1.0.0...
[1 of 1] Compiling Main             ( Main.hs, dist/build/HelloWorld/HelloWorld-tmp/Main.o )
Linking dist/build/HelloWorld/HelloWorld ...
haddockPhase
installing
Installing executable(s) in
/nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0/bin
Warning: The directory
/nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0/bin is not in
the system search path.
post-installation fixup
shrinking RPATHs of ELF executables and libraries in /nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0
shrinking /nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0/bin/HelloWorld
cannot find section .dynamic
stripping (with flags -S) in /nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0/bin 
patching script interpreter paths in /nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0
/nix/store/7n9ljx8ynrqa6hmximlrgrvsyyyf5hns-HelloWorld-0.1.0.0
λ nixos HelloWorld → tree result
result
|-- bin
|   `-- HelloWorld
`-- share
    `-- doc
        `-- x86_64-halvm-ghc-8.0.2
            `-- HelloWorld-0.1.0.0
                `-- LICENSE

5 directories, 2 files

For more information on nix-build, please consult the following link.

Additional Learning Resources