3.3 KiB
pkgs.callPackage
In the previous section, we used the import xxx.nix
syntax to import Nix files. This syntax simply returns the execution result of the file without any further processing.
Another method to import Nix files is pkgs.callPackage
. Its syntax is pkgs.callPackage xxx.nix { ... }
. However, unlike import
, the Nix file imported by pkgs.callPackage
must be a Derivation or a function that returns a Derivation. The result of pkgs.callPackage
is also a Derivation, which represents a software package.
So, what does a Nix file that can be used as a parameter for pkgs.callPackage
look like? You can refer to the hello.nix
, fcitx5-rime.nix
, vscode/with-extensions.nix
, and firefox/common.nix
files mentioned earlier. All of these files can be imported using pkgs.callPackage
.
When the xxx.nix
file used in pkgs.callPackage xxx.nix {...}
is a function (most Nix packages follow this pattern), the execution flow is as follows:
-
pkgs.callPackage xxx.nix {...}
first importsxxx.nix
to obtain the function defined within it. This function usually has parameters likelib
,stdenv
,fetchurl
, and sometimes additional custom parameters with default values. -
Then,
pkgs.callPackage
searches for a value matching the parameter names from the current environment. Parameters likelib
,stdenv
, andfetchurl
are defined in nixpkgs and will be found in this step. -
Next,
pkgs.callPackage
merges its second parameter,{...}
, with the attribute set obtained in the previous step. It then passes this merged set as the parameter to the function imported fromxxx.nix
for execution. -
Finally, the result of the function execution is a Derivation.
The common use case for pkgs.callPackage
is to import customized Nix packages and use them in Nix Modules.
For example, let's say we have a customized NixOS kernel configuration file named kernel.nix
, which uses the SBC's name and kernel source as its variable parameters:
{
lib,
stdenv,
linuxManualConfig,
src,
boardName,
...
}:
(linuxManualConfig {
version = "5.10.113-thead-1520";
modDirVersion = "5.10.113";
inherit src lib stdenv;
# File path to the generated kernel config file (`.config` generated by make menuconfig)
#
# Here, we use a special usage to generate a file path from a string.
configfile = ./. + "${boardName}_config";
allowImportFromDerivation = true;
})
We can use pkgs.callPackage ./kernel.nix {}
in any Nix Module to import and replace any of its parameters:
{ lib, pkgs, pkgsKernel, kernel-src, ... }:
{
# ......
boot = {
# ......
kernelPackages = pkgs.linuxPackagesFor (pkgs.callPackage ./pkgs/kernel {
src = kernel-src; # The kernel source is passed as a `specialArgs` and injected into this module.
boardName = "licheepi4a"; # The board name, used to generate the kernel config file path.
});
# ......
}
In the example above, we use pkgs.callPackage
to pass different src
and boardName
parameters to the function defined in kernel.nix
. This allows us to generate different kernel packages. By changing the parameters passed to pkgs.callPackage
, kernel.nix
can adapt to different kernel sources and development boards.