[LINUX] How to build Hello, World on #Nix

A note on how to build a program using Nix.

Basic flow

An overview of the basic build flow. First, create a default.nix file in your project directory.

> mkdir myproject && cd myproject

myproject> touch default.nix

Next, write stdenv.mkDerivation in default.nix. mkDerivation is a function used when creating a package on Nix.

default.nix


with import <nixpkgs> {};
stdenv.mkDerivation { ... }

After writing default.nix, run the nix-build command to build the package.

myproject> nix-build

After the build is finished, you will have a folder called result in your project directory. The built binary etc. will be included in this.

Minimum sample

Build the following C source code.

hello.c


#include <stdio.h>

int main(int argc, char *argv[]) {
  printf("Hello, world\n"); 
}

default.nix is written like this:

default.nix


with import <nixpkgs> {};
stdenv.mkDerivation {
  name = "hello";
  src = ./hello.c;
  buildCommand = ''
    gcc -Wall -O2 -o hello $src
    install -m555 -Dt $out/bin hello
  '';
}

At this point, the structure of the project looks like this

myproject> tree
.
├── default.nix
└── hello.c

Let's go

myproject> nix-build
these derivations will be built:
  /nix/store/l46b92csn5d9ics7zfs9yb51gb5n6y4r-hello.drv
building '/nix/store/l46b92csn5d9ics7zfs9yb51gb5n6y4r-hello.drv'...
/nix/store/0a3f6ddksy17jmfzasj2np999cgkrs8a-hello

After building, you will have a result directory.

myproject> tree -l
.
├── default.nix
├── hello.c
└── result -> /nix/store/0a3f6ddksy17jmfzasj2np999cgkrs8a-hello
    └── bin
        └── hello

In fact, result is a symbolic to nix / store / 0a3f ...-hello. Let's run the binary.

myproject> result/bin/hello
Hello, world

It worked fine.

Read what is written in default.nix

All you're doing with default.nix is passing the necessary arguments to stdenv.mkDerivation.

The argument of mkDerivation is

Has been passed.

name is the name of the package and src is the source code to build. In buildCommand, write the shell script required for the build.

In buildCommand, you can refer to the path passed to the argument key src as $ src. Also, $ out contains the path after the build (/ nix / store / 0a3f ...-hello).

Refactoring default.nix

To see the other features of mkDerivation, let's rewrite default.nix.

First, use pname and version instead of name. This will automatically name the package in the form <pname>-<version>.

deafult.nix


with import <nixpkgs> {};
stdenv.mkDerivation {
  pname = "hello";
  version = "0.1.0";  
  src = ./hello.c;
  buildCommand = ...;
}

Then stop writing buildCommand directly to default.nix and write the build script in a separate file.

builder.sh


source $stdenv/setup

gcc -Wall -O2 -o hello $src
install -m555 -Dt $out/bin hello

The first line, source $ stdenv / setup, is needed to set up the build environment on Nix. After writing the build script, pass the script path to builder.

default.nix


with import <nixpkgs> {};
stdenv.mkDerivation {
  pname = "hello";
  version = "0.1.0";  
  src = ./hello.c;
  builder = ./builder.sh;
}

Let's go

myproject> nix-build
these derivations will be built:
  /nix/store/j2vxh4xm6jarf0jnm9x3sywmr1nvxdhg-hello-0.1.0.drv
building '/nix/store/j2vxh4xm6jarf0jnm9x3sywmr1nvxdhg-hello-0.1.0.drv'...
/nix/store/i8l2rmiy708sz6n486yasgzshp044kpd-hello-0.1.0

You can see that the hash has changed by rewriting default.nix. The one you just built will not be overwritten, but a new build will be created in a separate file. If you re-tension the symbol, it seems that you can always return to the previous build.

Get the source from the web and build

Stop using the local source code and try downloading and building the source code on the web. Let's build GNU / hello. The project page is here.

Use fetchzip to download the source.

default.nix


stdenv.mkDerivation {
 ...
  src = fetchzip {
    url = "https://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz";
    sha256 = "1im1gglfm4k10bh4mdaqzmx3lm3kivnsmxrvl6vyvmfqqzljq75l";  
  };
  ...
}

fetchzip downloads the compressed source from the web and deploys it locally. The argument requires a hash such as sha256 as well as ʻurl`.

Use the nix-prefetch-url command to calculate the hash. The --unpack option is required for compressed files.

myproject> nix-prefetch-url --unpack 'https://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz'
unpacking...
[0.7 MiB DL]
path is '/nix/store/xsh1xgry2vsf6674jhc26q8k1bv4p76s-hello-2.10.tar.gz'
1im1gglfm4k10bh4mdaqzmx3lm3kivnsmxrvl6vyvmfqqzljq75l

GNU / hello can be built with ./configure; make; make install.

For a typical build like this, mkDerivation will build nicely, so you don't have to write builder.sh by hand. The whole default.nix looks like this:

default.nix


stdenv.mkDerivation rec {
  pname = "hello";
  version = "2.10";  
  src = fetchzip {
    url = "https://ftp.gnu.org/gnu/hello/${pname}-${version}.tar.gz";
    sha256 = "1im1gglfm4k10bh4mdaqzmx3lm3kivnsmxrvl6vyvmfqqzljq75l";  
  };
}

It's a small detail, but use $ {} for string interpolation in Nix. Don't forget rec.

Let's go

myproject> ls
default.nix

myproject> nix-build
these derivations will be built:
  /nix/store/q64l9f6d29zivah3sqrxlhpw8wmz3jrk-source.drv
  /nix/store/936zpfpmzxliinc69a49yn4dh67pgj6x-hello-2.10.drv
...

That's the basic build method.

Building Nix is environment agnostic, so you can build it on any PC with just one default.nix. I think it's worth using Nix just for this peace of mind.

Link to more detailed commentary

If you want to know more about mkDerivation, you can refer to the manual and Nix Pills.

In addition to fetchzip, there are also functions to download sources from GitHub and GitLab. They are also explained in the manual.

Unfortunately, the Nix manual is still evolving. Therefore, the manual is still lacking a lot of content. When actually building a program on Nix, the source of the Nixpkgs repository is very helpful.

Also, in order to handle mkDerivation freely, it is good to read the source of stdenv / setup.

Recommended Posts

How to build Hello, World on #Nix
How to display Hello world in python
Hello World on Django
[Latest] How to build Java environment on Ubuntu
How to build Java environment on Ubuntu (Linux)
How to register on pypi
How to build a Django (python) environment on docker
Hello World (beginners) on Django
How to build a Python environment on amazon linux 2
How to build a new python virtual environment on Ubuntu
How to install mysql-connector-python on mac
How to use Dataiku on Windows
Introduction to TensorFlow --Hello World Edition
Notes on how to use pywinauto
How to install graph-tool on macOS
How to install VMware-Tools on Linux
How to install pycrypto on Windows
How to deploy django-compressor on Windows
Notes on how to use featuretools
How to install OpenCV on Mac
How to run matplotlib on heroku
How to install PyPy on CentOS
How to use homebrew on Debian
Misunderstanding on how to connect cnn
How to use Nix package manager
How to install TensorFlow on CentOS 7
How to build MongoDB C driver
Notes on how to use doctest
How to install Maven on CentOS
Notes on how to write requirements.txt
How to install Go on Ubuntu
How to install music 21 on windows
Introduction to Ansible Part 1'Hello World !!'
Use python on Raspberry Pi 3 to illuminate the LED (Hello World)
How to build a Python environment using Virtualenv on Ubuntu 18.04 LTS
Hello world
How to build my own Linux server
How to install aws-session-manager-plugin on Manajro Linux
How to build a sphinx translation environment
How to read pydoc on python interpreter
How to install drobertadams / toggl-cli on Mac
How to use mecab, neologd-ipadic on colab
How to update php on Amazon linux 2
How to use Google Assistant on Windows 10
How to erase Python 2.x on Mac.
How to display emoji on Manjaro Linux
Memorandum on how to use gremlin python
How to install packages on Alpine Linux
How to install Anisble on Amazon Linux 2
How to switch mouse operations on CentOS
How to install richzhang / colorization on Windows 10
How to update security on CentOS Linux 8
How to install Apache (httpd) on CentOS7
How to install php7.4 on Linux (Ubuntu)
How to install Eclipse GlassFish 5.1.0 on CentOS 7
Flask tutorial (from installation to hello world)
How to install Apache (httpd) on CentOS8
How to test on a Django-authenticated page
How to run Cython on OSX Memo
How to find large files on Linux
How to install NumPy on Raspberry Pi