mirror of
https://github.com/ryan4yin/nixos-and-flakes-book
synced 2024-12-20 09:23:13 +00:00
69 lines
3.3 KiB
Markdown
69 lines
3.3 KiB
Markdown
# pkgs.callPackage
|
||
|
||
前面我们介绍并大量使用了 `import xxx.nix` 来导入 Nix 文件,这种语法只是单纯地返回该文件的执行结果,不会对该结果进行进一步处理。
|
||
比如说 `xxx.nix` 的内容是形如 `{...}: {...}`,那么 `import xxx.nix` 的结果就是该文件中定义的这个函数。
|
||
|
||
`pkgs.callPackage` 也是用来导入 Nix 文件的,它的语法是 `pkgs.callPackage xxx.nix { ... }`. 但跟 `import` 不同的是,它导入的 nix 文件内容必须是一个 Derivation 或者返回 Derivation 的函数,它的执行结果一定是一个 Derivation,也就是一个软件包。
|
||
|
||
那可以作为 `pkgs.callPackge` 参数的 nix 文件具体长啥样呢,可以去看看我们前面举例过的 `hello.nix` `fcitx5-rime.nix` `vscode/with-extensions.nix` `firefox/common.nix`,它们都可以被 `pkgs.callPackage` 导入。
|
||
|
||
当 `pkgs.callPackge xxx.nix {...}` 中的 `xxx.nix`,其内容为一个函数时(绝大多数 nix 包都是如此),执行流程如下:
|
||
|
||
1. `pkgs.callPackge xxx.nix {...}` 会先 `import xxx.nix`,得到其中定义的函数,该函数的参数通常会有 `lib`, `stdenv`, `fetchurl` 等参数,以及一些自定义参数,自定义参数通常都有默认值。
|
||
2. 接着 `pkgs.callPackge` 会首先从当前环境中查找名称匹配的值,作为将要传递给前述函数的参数。像 `lib` `stdenv` `fetchurl` 这些都是 nixpkgs 中的函数,在这一步就会查找到它们。
|
||
3. 接着 `pkgs.callPackge` 会将其第二个参数 `{...}` 与前一步得到的参数集(attribute set)进行合并,得到一个新的参数列表,然后将其传递给该函数并执行。
|
||
4. 函数执行结果是一个 Derivation,也就是一个软件包。
|
||
|
||
这个函数比较常见的用途是用来导入一些自定义的 Nix 包。
|
||
|
||
比如说我们自定义了一个 NixOS 内核配置 `kernel.nix`,并且将开发版名称与内核源码作为了可变更参数:
|
||
|
||
```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;
|
||
})
|
||
```
|
||
|
||
那么就可以在任意 Nix Module 中使用 `pkgs.callPackage ./hello.nix {}` 来导入并使用它,并且替换它的任意参数。
|
||
|
||
```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.
|
||
});
|
||
|
||
# ......
|
||
}
|
||
```
|
||
|
||
就如上面所展示的,通过 `pkgs.callPackage` 我们可以给 `kernel.nix` 定义的函数传入不同的 `src` 与 `boardName`,来生成不同的内核包,这样就可以使用同一份 `kernel.nix` 来适配不同的内核源码与不同的开发板了。
|
||
|
||
## 参考
|
||
|
||
- [Chapter 13. Callpackage Design Pattern - Nix Pills](https://nixos.org/guides/nix-pills/callpackage-design-pattern.html)
|