Nix packages

From wikinotes
(Redirected from Nixpkgs packages)

Derivations are the primary abstraction of nix.
Within a derivation, you define the build instructions for a package.

Documentation

official docs: expressions https://nixos.org/nix/manual/#chap-writing-nix-expressions
stdenv.mkDerivation docs http://blog.ielliott.io/nix-docs/stdenv-mkDerivation.html
nixpkgs manual https://nixos.org/nixpkgs/manual/#sec-tools-of-stdenv
package attributes https://nixos.org/nixpkgs/manual/#sec-standard-meta-attributes

stdenv

stdenv is a meta-package that includes a set of common unix tools for building packages.

  • gcc
  • gnu-coreutils
  • gnu-diffutils
  • gnu-findutils
  • gnu-tar
  • make
  • bash
  • patch

Creating Packages

Project Packaging

Project builds/environments can be managed using nix by adding a default.nix
to the project-root that describes the environment and build instructions.

# yourpackage/default.nix

{ pkgs ? import <nixpkgs> {} }:

with pkgs; # use pkgs namespace

let
  inherit hello;

in
  pkgs.stdenv.mkDerivation {
    pname = "foo";            # package name
    version = "1.0.0";        # package version
    buildInputs = [ hello ];  # nix requirements
    builder = ./builder.sh;   # script invoked to perform build
    HELLO_ENV = "hello";      # environment variables
    shellHook = ''
        export PYTHONPATH+=":$(pwd)/plugin"
    ''
}

Development Env/Tools

You may have personal requirements (like vim) that you want in your dev environment.
You can use overrides/overlays to add these.

wrap default.nix in shell.nix


If your project defines a default.nix, without a shell.nix,
You can define a .gitignored shell.nix that loads/overrides your package with a modified attribute set.

shell.nix

# shell.nix
{ pkgs ? import <nixpkgs> {} }:
let
  pkg = import ./default.nix {};

in
  pkg.overrideAttrs(
    old: { 
      buildInputs = old.buildInputs ++ [ pkgs.vim pkgs.hello ]; 
      # 'old' refers to our original default.nix
      # add/change any attributes you'd like
    }
  )

default.nix

# local.nix
{ pkgs ? import <nixpkgs> {}, shell ? { inputs = []; } }:
let

in
  pkgs.stdenv.mkDerivation {
    name = "foo";
    buildInputs = [ pkgs.ripgrep ] ++ shell.inputs;
    HELLO_ENV="hello";
  }

add dev-reqs from config.nix, wrap default.nix in shell.nix


# ~/.config/nixpkgs/config.nix
{ pkgs ? import <nixpkgs> {} }:
{
  vim-dev-base = {
    buildInputs = [ pkgs.vim pkgs.ripgrep ];
  };
}
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
let
  pkg = import ./default.nix {};
  config = pkgs.config

in
  pkg.overrideAttrs(
    old: { 
      buildInputs = old.buildInputs ++ config.vim-dev-base.buildInputs; 
    }
  )

etc...


nixpkgs Repo Packaging

Nixpkgs repos are git projects that expose several nix packages.
They also use default.nix to describe builds, but the sourcecode is generally
retrieved from elsewhere in tarballs etc. and the build manages it's download/extraction/build.

pkgs/top-level/all-packages.nix

nixpkgs repo uses this file like a header file.
It defines all available packages as attributes with arguments.
Attributes may refer to other attributes within arguments.

To expose your package within nixpkgs, add it as an attribute here.

# pkgs/top-level/all-packages.nix

# NOTE: The real all-packages.nix appears to vary from this a bit,
#       I'll need to revisit this.

# ...

rec {
  # explicitly sets an attribute, determined by function in .../hello/ex-1
  # it's arguments fetchurl, stdenv, perl are set here.
  # (equivalent to { fetchurl=fetchurl; stdenv=stdenv; perl=perl; } )
  hello = import ../applications/misc/hello/ex-1 {
    inherit fetchurl stdenv perl;
  };

  # concise variation of the above, satisfies arguments automatically from
  # set of available nixpkgs
  perl = callPackage ../development/interpreters/perl { };

  # you may also set/override callPackage arguments
  fetchurl = callPackage ../build-support/fetchurl { stdenv=stdenv; };

  # ...
}

pkgs/applications/misc/hello/default.nix

This defines your derivation. It contains a function that accepts requirements,
and provides instructions on how to build your package.

# pkgs/applications/misc/hello/default.nix
# NOTE: relpath is arbitrary, but this matches official nixpkgs

{ stdenv, fetchurl, perl }:     # declares a function in this file, with 3x arguments. (each is a required nix package)

stdenv.mkDerivation {           # function call to build something
  name = "hello-2.1.1"; 3       # attribute (in this case name/version)
  builder = ./builder.sh;       # script invoked to perform build. if not provided uses `configure; make; make install`
  src = fetchurl {              # download this file before running `builder`
    url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz;
    sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465";
  };
  # perl=perl;                    # non-nix attributes are set as environment variables. here, this refers to the package 'perl'
  inherit perl;                   # equivalent to 'perl=perl;', but can accept multiple arguments
}

builder script

You can use whatever you'd like for the build script (it does not have to be shellscript),
but nix provides the helper library [ stdlib] which is designed to make your life simpler.

Note that you can shorten your builder.sh using nix's genericBuild executable.
It will extract, change directory, build, and install your package automatically.
See stdenv/phases documentation in nixpkgs manual https://nixos.org/nixpkgs/manual/ .

The full setup/teardown of the build process is outlined here: https://nixos.org/nix/manual/#ssec-derivation

Here are a couple of examples


pkgs/applications/misc/hello/builder.sh (explicit)


This example is simple, but explicit. It essentially replicates the
default genericBuild behaviour.

# pkgs/applications/misc/hello/builder.sh

# NOTE: script is invoked with `set -e`
# $stdenv is provided by mkDerivation. This is required?
source $stdenv/setup      


# the rest is just build instructions
PATH=$perl/bin:$PATH

tar xvfz $src
cd hello-*
./configure --prefix=$out
make
make install

pkgs/application/misc/hello/builder.sh (using genericBuild)


# pkgs/application/misc/hello/builder.sh

buildInputs="$perl"   # may be set in default.nix
source $stdenv/setup
genericBuild          # extract, cd, configure, make, make install

pkgs/application/misc/complex/builder.sh (using genericBuild, with phases)


You can also configure the phases of your build. See the phases section of the official documentation for all available options.

# pkgs/application/misc/hello/builder.sh

source $stdenv/setup

buildPhase() {
  echo "... this is my custom build phase ..."
  gcc foo.c -o foo
}

installPhase() {
  mkdir -p $out/bin
  cp foo $out/bin
}

genericBuild

Alternatively, you can provide these functions from your default.nix

# pkgs/application/misc/hello/default.nix

stdenv.mkDerivation {
  name = "fnord-4.5";
  ...
  buildPhase = ''
    gcc foo.c -o foo
  '';
  installPhase = ''
    mkdir -p $out/bin
    cp foo $out/bin
  '';
}

Using Packages

Once you have defined a package, you can use nix-env -i yourpackage.
But you probably want to test it before installing it.

nix-env -i     # install your package
nix-build      # build package at cwd
nix-shell      # interactive shell with requirements of package at cwd