cleverca22
8/28/2016 - 9:05 AM

Nix package development notes

Nix package development notes

Some notes for tricky things I've run into while packaging things for Nix...

Searching through package expressions in the master branch of nixpkgs

There is a code search available here. It's considerably more useful and accurate than GitHub's search.

Creating your own package 'repository'

This article explains that.

Stepping through builder steps in your custom packages

  1. Create a temporary building folder in your repository (or elsewhere) and enter it: mkdir test && cd test
  2. nix-shell ../main.nix -A packagename (assuming the entry point for your custom repository is main.nix in the parent directory)
  3. Run the phases individually by entering their name (for a default phase) or doing something like eval "$buildPhase" (for an overridden phase) in the Nix shell - a summary of the common ones: unpackPhase, patchPhase, configurePhase, buildPhase, checkPhase, installPhase, fixupPhase, distPhase

More information about these phases can be found here. If you use a different builder, you may have a different set of phases.

Don't forget to clear out your test folder after every attempt!

Using dependencies in your build phases

You can just use string interpolation to add a dependency path to your script. For example:

{
  # ...
  preBuildPhase = ''
    ${grunt-cli}/bin/grunt prepare
  '';
  # ...
}

Source roots that need to be renamed before they can be used

Some applications (such as Brackets) are very picky about the directory name(s) of your unpacked source(s). In this case, you might need to rename one or more source roots before cding into them.

To accomplish this, do something like the following:

{
  # ...
  sourceRoot = ".";
  
  postUnpack = ''
    mv brackets-release-${version} brackets
    mv brackets-shell-${shellBranch} brackets-shell
    cd brackets-shell;
  '';
  # ...
}

This keeps Nix from trying to move into the source directories immediately, by explicitly pointing it at the current (ie. top-most) directory of the environment.

Error: error: cannot coerce a function to a string

Probably caused by a syntax ambiguity when invoking functions within a list. For example, the following will throw this error:

{
  # ...
  srcs = [
    fetchurl {
      url = "https://github.com/adobe/brackets-shell/archive/${shellBranch}.tar.gz";
      sha256 = shellHash;
    }
    fetchurl {
      url = "https://github.com/adobe/brackets/archive/release-${version}.tar.gz";
      sha256 = "00yc81p30yamr86pliwd465ag1lnbx8j01h7a0a63i7hsq4vvvvg";
    }
  ];
  # ...
}

This can be solved by adding parentheses around the invocations:

{
  # ...
  srcs = [
    (fetchurl {
      url = "https://github.com/adobe/brackets-shell/archive/${shellBranch}.tar.gz";
      sha256 = shellHash;
    })
    (fetchurl {
      url = "https://github.com/adobe/brackets/archive/release-${version}.tar.gz";
      sha256 = "00yc81p30yamr86pliwd465ag1lnbx8j01h7a0a63i7hsq4vvvvg";
    })
  ];
  # ...
}

buildInputs vs. nativeBuildInputs?

More can be found here.

  • buildInputs: Dependencies for the (target) system that your built package will eventually run on.
  • nativeBuildInputs: Dependencies for the system where the build is being created.

The difference only really matters when cross-building - when building for your own system, both sets of dependencies will be exposed as nativeBuildInputs.

QMake ignores my PREFIX/INSTALL_PREFIX/etc. variables!

QMake does not have a standardized configuration variable for installation prefixes - PREFIX and INSTALL_PREFIX only work if the project files for the software you're building specify it explicitly.

If the project files have a hardcoded path, there's still a workaround to install it in $out anyway, without source code or project file patches:

{
  # ...
  preInstall = "export INSTALL_ROOT=$out";
  # ...
}

This INSTALL_ROOT environment variable will be picked up and used by make install, regardless of the paths specified by QMake.