Building and installing a C project with Nix
Today I learned how to build and install a simple C project on Nix(OS).
After some reading on the Internet π, I finally understood the basics of building and installing a package from C sources using a Nix expression file (the .nix
file in the following examples).
#packaging #coding #nix #diary #c
The expression file uses the standard build environment π§°. Essentially, this environment abstracts the traditional Makefile
based build proces (i.e., make && make install
).
For learning purposes, I decided to package my hobby project, the text-based journaling program diary
π.
Writing the Nix expression file
I built the expression file based on a an example from the Nix book.
The Nix expression file diary.nix
to install the stable version of the diary
program fetches the source by tag from the Git repository:
let
pkgs = import <nixpkgs> { };
in
pkgs.stdenv.mkDerivation {
name = "diary";
version = "v0.10";
buildInputs = with pkgs; [
ncurses
curlFull
lttng-ust
];
src = pkgs.fetchgit {
url = "https://git.in0rdr.ch/diary.git";
rev = "refs/tags/v0.10";
hash = "sha256-jDPfqUjf0ZETYqPxvEJ2/YFFjNsF7yvVQiThc5yMvjc=";
};
installPhase = ''
install -d $out/bin
install -d $out/share/man/man1
install -m755 diary $out/bin/
install -m644 man1/diary.1 $out/share/man/man1/
'';
}
The mkDerivation
call does most of the work. There we define the package name
and version
, as well all of the dependencies required to build the project. In this case, the diary
program depends on the curl
and ncurses
libraries as well as the lttng
tracing library.
The source code src
can be fetched conveniently from Git (using the fetchgit
βbuilderβ) or from other remote sources (see related βfetchβ builtin functions).
To build a nightly release from the master branch, I only had to slightly tune the src
of the unstable Nix expression:
src = pkgs.fetchgit {
url = "https://git.in0rdr.ch/diary.git";
hash = "sha256-laKIVxfqJqBkB2d0F8tOOnpAXXRzHFfpjhAzZT8MX8k=";
};
The sha256 hash can be obtained using nix-prefetch-git
:
# get hash for the specific tag/release
nix-prefetch-git https://git.in0rdr.ch/diary.git --rev refs/tags/v0.10
# get hash for latest nightly build from master branch
nix-prefetch-git https://git.in0rdr.ch/diary.git
Finally, the installPhase
needed a bit of tuning and has a small difference to what is commonly used in a Makefile
on a traditional Linux distribution. But that was not too hard either, I simply had to translate my install
target from the already existing Makefile
.
The install
target:
install: $(TARGET)
install -m755 $(TARGET) $(BINDIR)/$(TARGET)
install -d $(MANDIR)/man1
install -m644 $(MAN1) $(MANDIR)/$(MAN1)
The corresponding Nix installPhase
:
install -d $out/bin
install -d $out/share/man/man1
install -m755 diary $out/bin/
install -m644 man1/diary.1 $out/share/man/man1/
Very similar indeed. One point to note here is that the fixup
phase will automatically install the man pages to the correct location.
Building and installing the C project
Once the expression file is written, building and installing the program is a peace of cake π°:
# Build stable package
nix-build nix/diary.nix
# Build latest nightly version
nix-build nix/diary-unstable.nix
To install the package from the expression file to the user environment:
# Install stable package
nix-env -i -f nix/diary.nix
# Install latest nightly version
nix-env -i -f nix/diary-unstable.nix
You can even verify the location of the man page by using manpath -q
or query the installed package with nix-env -q
.
Next steps
Now that we have drafted the basic expression file, we might also add it to the nixpkgs
repository on GitHub. I haven't checked the contributor requirements in detail yet. Hit me up on IRC #p0c or on Mastodon if you want to contribute to the discussion or have some inputs for me (yes, I still consider my self a Nix noobie π).