Nix packages: Difference between revisions
Line 52: | Line 52: | ||
in | in | ||
pkgs.stdenv.mkDerivation { | pkgs.stdenv.mkDerivation { | ||
name = " | pname = "foo"; # package name | ||
version = "1.0.0"; # package version | |||
buildInputs = [ hello ]; # nix requirements | buildInputs = [ hello ]; # nix requirements | ||
builder = ./builder.sh; # script invoked to perform build | builder = ./builder.sh; # script invoked to perform build |
Latest revision as of 23:00, 5 September 2021
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 adefault.nix
, without ashell.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 usedefault.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'sgenericBuild
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
defaultgenericBuild
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 installpkgs/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 installpkgs/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 } genericBuildAlternatively, 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