# pkgs.callPackage In the previous section, we used `import xxx.nix` to import Nix files multiple times. This syntax simply returns the execution result of the file without any further processing. `pkgs.callPackage` is also used to import Nix files. Its syntax is `pkgs.callPackage xxx.nix { ... }`. However, unlike `import`, the Nix file imported by it must be a Derivation or a function that returns a Derivation. Its result is also a Derivation (a software package). So, what does the Nix file that can be used as a parameter of `pkgs.callPackge` look like? You can take a look at the `hello.nix`, `fcitx5-rime.nix`, `vscode/with-extensions.nix`, and `firefox/common.nix` files we mentioned earlier. They can all be imported by `pkgs.callPackage`. When the `xxx.nix` used in `pkgs.callPackge xxx.nix {...}` is a function (most Nix packages are like this), the execution flow is as follows: 1. `pkgs.callPackge xxx.nix {...}` first imports `xxx.nix` to get the function defined in it. The parameters of this function usually have `lib`, `stdenv`, `fetchurl`, and other parameters, as well as some custom parameters that usually have default values. 2. Then, `pkgs.callPackge` looks up the value matching the name from the current environment as the parameter to be passed to the function. Parameters like `lib`, `stdenv`, and `fetchurl` are defined in nixpkgs and will be found in this step. 3. Next, `pkgs.callPackge` merges its second parameter `{...}` with the attribute set obtained in the previous step and passes it to the function imported from `xxx.nix` to execute it. 4. Finally, we get a Derivation as the result of the function execution. The common usage of `pkgs.callPackage` is to import customized Nix packages and use them in Nix Modules. For example, suppose we have customized a NixOS kernel configuration `kernel.nix`, which uses the SBC's name and kernel source as its variable parameters: ```nix { 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(the `.config` generated by make menuconfig) # # here is a special usage to generate a file path from a string configfile = ./. + "${boardName}_config"; allowImportFromDerivation = true; }) ``` Then we can use `pkgs.callPackage ./kernel.nix {}` in any Nix Module to import and replace any of its parameters: ```nix { lib, pkgs, pkgsKernel, kernel-src, ... }: { # ...... boot = { # ...... kernelPackages = pkgs.linuxPackagesFor (pkgs.callPackage ./pkgs/kernel { src = kernel-src; # 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. }); # ...... } ``` Similarly to the example above, we can 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 it, `kernel.nix` can be used to adapt to different kernel sources and development boards. ## References - [Chapter 13. Callpackage Design Pattern - Nix Pills](https://nixos.org/guides/nix-pills/callpackage-design-pattern.html)