Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
What does Nixpkgs' `callPackage` do?
callPackage
is a complex function (reasons include the Nix language being lazy, usage of fixed-point evaluation, overrides, etc.), and this complexity steals the spotlight from what this function actually does and why is it so useful.
There are a plethora of online resources about this topic (see below), but I couldn't find a simple, concise summary.
-
[
nix.dev
] Package parameters and overrides with callPackage — nix.dev documentation -
[
Nix Pills
] 13. Callpackage Design Pattern -
[
Nix-Book
] Imports and callPackage - Nix-Book -
Nixpkgs commit and email introducing
callPackage
-
[
stackoverflow
] Where iscallPackage
defined in the Nixpkgs repo (or how to find Nix lambda definitions in general)? -
[
NixOS Discourse
] Where iscallPackage
defined exactly? (part 2) - Help - NixOS Discourse -
[
Nixpkgs repo
] Issue #36354 - Document what callPackage does and its preconditions -
[
Summer of Nix
]callPackage
, a tool for the lazy -
[
NixOS & Flakes Book
]pkgs.callPackage
1 answer
For the record, this write-up is not better than any of the resources listed in the question; writing it simply helped me better understand callPackage
.
Level 0. Poor, but short
callPackage f attr_set
will
- call function
f
with inputs automatically supplied fromattr_set
and Nixpkgs - make the resulting attribute set overridable.
callPackage
is used overwhelmingly with functions that produce a derivation. Building a project can require a lot of dependencies that won't have to be specified manually this way, and callPackage
also makes it possible to configure "Nix derivation expressions" after callPackage
has been called using overrides. (This email goes has the full rationale.)
"Nix derivation expression" is just a personal term, not an official one, that I use to refer to an attribute set that represents a store derivation in terms of the Nix language before instantiation.
Level 1. Wordier and still inexact
callPackage
accepts 2 inputs:
-
a function that takes as input an attribute set
e.g.,{ stdenv, miez, lofa ? 27 }: { inherit stdenv miez lofa; }
-
an attribute set that must be a subset of the input function's input attribute set
e.g., in the case of the example in item 1., this would be ok:{ miez = 7; lofa = 9; }
callPackage
will
-
call the input function with an attribute set whose attributes are supplied from
- the attribute set in
callPackage
's 2nd argument - a subset of the Nixpkgs package (attribute) set1
- the attribute set in
-
make the resulting attribute set overridable.
Level 2. More precise but also more abstruse
callPackage :: ( attr_set_function | path_to_file_with_attr_set_function )
-> constrained_attr_set
-> ( overridable_attr_set | arbitrary_nix_value )
attr_set_function :: input_attr_set -> attr_set
The Nix language is dynamically typed, so this is just a personal notation.
where
-
input_attr_set
is a regular attribute set with caveats depending on whether its attributes are Nixpkgs or not:-
IN Nixpkgs
If the attribute names match attributes in the limited subset of Nixpkgs package set1, then these won't have to be specified inconstrained_attr_set
ascallPackage
will auto-populate them. -
NOT in Nixpkgs
These either must have a default value or have to be specified inconstrained_attr_set
.
-
-
constrained_attr_set
is an attribute set that can only be a subset ofattr_set_function
's input attribute set. -
overridable_att_set
- See this section of thenix.dev
tutorial.
Level 3. Source
splicedPackagesWithXorg = splicedPackages // builtins.removeAttrs splicedPackages.xorg [
"callPackage"
"newScope"
"overrideScope"
"packages"
];
# ...
callPackage = pkgs.newScope { };
callPackages = ...;
newScope = extra: lib.callPackageWith (splicedPackagesWithXorg // extra);
callPackages
(note the extra s
!) is also defined here, but omitted it, lest I muddy the waters even more.
callPackageWith
is quite long, so only posting the link, but the resources in the question explain the nitty-gritty - and the core of it is this line:
callPackage = f: args:
f ((builtins.intersectAttrs (builtins.functionArgs f) pkgs) // args);
... and this is an email from 2009 that introduces it.
Examples
NOTE
The termpkgs
below will refer to the Nixpkgs package set. Such as the result of any of the following calls innix repl
:
pkgs = import
<nixpkgs>
{}
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/06278c77b5d162e62df170fec307e83f1812d94b.tar.gz") {}
- ... and so on
-
✅
pkgs.callPackage ({ lib, stdenv }: { ... }) {}
lib
andstdenv
are valid attributes in Nixpkgs, so these will be auto-populated from there. Roughly equivalent to:
pkgs.callPackage ({ lib, stdenv }: ... }) { lib = pkgs.lib; stdenv = pkgs.stdenv; }
-
✅
pkgs.callPackage ({ lib, stdenv, lofa ? 27 }: { ... }) {}
Same things apply as in the previous item, except that Nixpkgs has no
lofa
attribute, but there is a default value provided for it, so it will work. -
✅
( pkgs.callPackage ({ lib, stdenv, lofa }: { inherit lofa lib; }) { lofa = 27; lib = "whatever"; } )
Same as in previous item, but attributes
lofa
andlib
are explicitly provided. -
✅
let id = x: x; in pkgs.callPackage id {}
callPackage
's input function (1st parameter) is called with an attribute set, so this still works. -
❌
pkgs.callPackage (i: i + 2) {}
callPackage
will choke becausei
will be an attribute set and the+
operator will try to coerce it into a string. -
❌
pkgs.callPackage ({ lib, stdenv, lofa }: { inherit lofa; }) {}
will raise
error: Function called without required argument "lofa"
. -
✅
$ echo "{lib, stdenv, lofa ? 27}: {inherit lofa;}" > f.nix $ nix repl nix-repl> pkgs = import <nixpkgs> {} nix-repl> pkgs.callPackage ./f.nix {}
Providing a valid file system path containing a Nix expression (that conforms to what
callPackage
is accepting) works too as the file will be automatically imported first.
The result of attr_set_function
is usually a Nix derivation expression (which is an attribute set denoting a derivation - or something like it; look this up).
0 comment threads