# 自定义软件包

以下说明假定你是从官方的 [tar 发行版压缩包](https://github.com/zfsonlinux/zfs/releases/latest)（版本 0.8.0 或更新）或直接从 [git 仓库](https://github.com/zfsonlinux/zfs) 进行构建。大多数用户不需要这样做，应优先使用发行版提供的软件包。一般而言，发行版的软件包集成度更高、经过广泛测试、支持更完善。然而，如果你选择的发行版未提供软件包，或者你是开发者并想自己构建，下面是操作方法。

首先需要注意的是，构建系统能够生成几种不同类型的软件包。要选择的软件包类型取决于你的平台支持情况以及具体需求。

* **DKMS** 软件包只包含用于重建内核模块的源代码和脚本。安装 DKMS 软件包后，将为所有可用内核构建内核模块。此外，当更新内核时，会自动为该内核构建新的内核模块。这对于经常接收内核更新的桌面系统尤其方便。缺点是由于 DKMS 软件包从源代码构建内核模块，因此需要完整的开发环境，这对于大规模部署可能不合适。
* **kmods** 软件包是针对特定内核版本编译的二进制内核模块。这意味着如果你更新内核，必须编译、安装新的 kmod 软件包。如果你不经常更新内核，或者管理着大批量系统，那么 kmod 软件包是个不错的选择。
* **kABI-tracking kmod** 软件包类似于标准的二进制 kmods，可用于企业级 Linux 发行版，如 Red Hat 和 CentOS。这些发行版提供稳定的 kABI（内核应用二进制接口），可在提供的新版本发行版内核上使用相同的二进制模块。注意，这些软件包并不完全遵循 Red Hat 的规则，因此在新内核上有小概率失败的可能性。概率较低，但我们建议在生产服务器上使用这些构建时禁用自动内核更新。

在默认情况下，构建系统将生成用户软件包，并同时生成 DKMS 和 kmod 风格的内核软件包（如果可能）。用户软件包可与任一内核软件包一起使用，在内核更新时无需重新构建用户软件包。你也可以通过仅构建 DKMS 或 kmod 软件包来简化构建过程，如下所示。

请注意，当直接从 git 仓库构建时，必须首先运行 *autogen.sh* 脚本来生成 *configure* 脚本。这需要安装对应发行版的软件包 GNU autotools。要执行任何构建，必须安装该发行版所需的所有开发工具和头文件。

需要注意，如果当前运行的内核的开发内核头文件未安装，将无法正确编译模块。

* [Red Hat、CentOS 和 Fedora](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Custom%20Packages.html#red-hat-centos-and-fedora)
* [Debian 和 Ubuntu](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Custom%20Packages.html#debian-and-ubuntu)

## RHEL、CentOS 和 Fedora

确保已安装构建最新 ZFS 2.1 版本所需的软件包：

* **RHEL/CentOS 7**：

```sh
sudo yum install epel-release gcc make autoconf automake libtool rpm-build libtirpc-devel libblkid-devel libuuid-devel libudev-devel openssl-devel zlib-devel libaio-devel libattr-devel elfutils-libelf-devel kernel-devel-$(uname -r) python python2-devel python-setuptools python-cffi libffi-devel ncompress
sudo yum install --enablerepo=epel dkms python-packaging
```

**注意：** RHEL/CentOS 7 生命周期已结束。在下面的安装说明中请使用 dnf 而非 yum。

* **RHEL/CentOS 8**：

```sh
sudo dnf install --skip-broken epel-release gcc make autoconf automake libtool rpm-build kernel-rpm-macros libtirpc-devel libblkid-devel libuuid-devel libudev-devel openssl-devel zlib-devel libaio-devel libattr-devel elfutils-libelf-devel kernel-devel-$(uname -r) kernel-abi-stablelists-$(uname -r | sed 's/\.[^.]\+$//') python3 python3-devel python3-setuptools python3-cffi libffi-devel ncompress
sudo dnf install --skip-broken --enablerepo=epel --enablerepo=powertools python3-packaging dkms
```

* **RHEL/CentOS 9**：

```sh
sudo dnf config-manager --set-enabled crb
sudo dnf install --skip-broken epel-release gcc make autoconf automake libtool rpm-build kernel-rpm-macros libtirpc-devel libblkid-devel libuuid-devel libudev-devel openssl-devel zlib-devel libaio-devel libattr-devel elfutils-libelf-devel kernel-devel-$(uname -r) kernel-abi-stablelists-$(uname -r | sed 's/\.[^.]\+$//') python3 python3-devel python3-setuptools python3-cffi libffi-devel
sudo dnf install --skip-broken --enablerepo=epel python3-packaging dkms
```

* **Fedora 41**：

```sh
sudo dnf install gcc make autoconf automake libtool rpm-build kernel-rpm-macros libtirpc-devel libblkid-devel libuuid-devel systemd-devel openssl-devel zlib-ng-compat-devel libaio-devel libattr-devel libffi-devel libunwind-devel kernel-devel-$(uname -r) python3 python3-devel openssl ncompress
sudo dnf install python3-packaging dkms
```

[下载源代码](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Custom%20Packages.html#get-the-source-code)。

### DKMS

基于 rpm 的 DKMS 和用户软件包可以按如下方式构建：

```sh
$ cd zfs
$ ./configure
$ make -j1 rpm-utils rpm-dkms
$ sudo dnf install *.$(uname -m).rpm *.noarch.rpm
```

### kmod

在构建 kmod 软件包时，需要注意的关键点是必须指定特定的 Linux 内核。在配置阶段，构建系统会根据经验猜测你希望针对哪个内核构建。然而，如果 configure 找不到你的内核开发头文件，或者你想针对不同内核构建，则必须使用选项 *--with-linux* 和 *--with-linux-obj* 指定确切路径。

```sh
$ cd zfs
$ ./configure
$ make -j1 rpm-utils rpm-kmod
$ sudo dnf install *.$(uname -m).rpm *.noarch.rpm
```

> **注意：**
>
> Fedora 41 Workstation 内置 rpm 软件包 zfs-fuse，会妨碍安装你自己的软件包。在执行 `dnf install` 之前请先仅删除该软件包：

```sh
$ sudo rpm -e --nodeps zfs-fuse
```

### kABI-tracking kmod

构建 kABI-tracking kmod 的过程与构建普通 kmod 几乎相同。然而，仅在该发行版支持稳定 kABI 的情况下，才会生成可被多个内核使用的二进制文件。要请求 kABI-tracking 软件包，必须在 configure 时传入选项 *--with-spec=redhat*。

请注意，这些软件包并不完全遵循 Red Hat 的规则，因此有小概率在新内核上无法使用。我们建议在生产服务器上使用这些构建时禁用自动内核更新。

> **注意：**
>
> 这种类型的软件包在 Fedora 上不可用。

```sh
$ cd zfs
$ ./configure --with-spec=redhat
$ make -j1 rpm-utils rpm-kmod
$ sudo dnf install *.$(uname -m).rpm *.noarch.rpm
```

### Fedora 41 使用 kmod 的安全启动

在使用 UEFI 和安全启动的现代计算机上，将无法加载 zfs 内核模块：

```sh
$ sudo modprobe zfs
modprobe: ERROR: could not insert 'zfs': Key was rejected by service
```

可以选择禁用安全启动，或者**只需一次性**创建自定义机器所有者密钥（MOK），并使用该密钥手动签名当前及未来的模块：

```sh
$ sudo mkdir /etc/pki/mok
$ cd /etc/pki/mok
$ sudo openssl req -new -x509 -newkey rsa:2048 -keyout LOCALMOK.priv -outform DER -out LOCALMOK.der -nodes -days 36500 -subj "/CN=LOCALMOK/"
$ sudo mokutil --import LOCALMOK.der
```

Mokutil 会要求你创建并记住密码，然后重启计算机，UEFI 将要求导入你的密钥：

```sh
选择 "Enroll MOK"、“Continue”、“Yes”，输入 mokutil 的密码，“Reboot”
```

之后可使用该 MOK 手动签名 zfs 内核模块：

```sh
$ rpm -ql kmod-zfs-$(uname -r) | grep .ko
/lib/modules/6.11.8-300.fc41.x86_64/extra/zfs/spl.ko
/lib/modules/6.11.8-300.fc41.x86_64/extra/zfs/zfs.ko
```

```
$ sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 /etc/pki/mok/LOCALMOK.priv /etc/pki/mok/LOCALMOK.der /lib/modules/$(uname -r)/extra/zfs/spl.ko
$ sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 /etc/pki/mok/LOCALMOK.priv /etc/pki/mok/LOCALMOK.der /lib/modules/$(uname -r)/extra/zfs/zfs.ko
```

加载模块，验证其已激活：

```sh
$ sudo modprobe zfs

$ lsmod | grep zfs
zfs                  6930432  0
spl                   155648  1 zfs
```

## Debian 和 Ubuntu

确保已安装所需的软件包：

```sh
sudo apt install alien autoconf automake build-essential debhelper-compat dh-dkms dh-python dkms fakeroot gawk libaio-dev libattr1-dev libblkid-dev libcurl4-openssl-dev libelf-dev libffi-dev libpam0g-dev libssl-dev libtirpc-dev libtool libudev-dev linux-headers-generic po-debconf python3 python3-all-dev python3-cffi python3-dev python3-packaging python3-setuptools python3-sphinx uuid-dev zlib1g-dev
```

[获取源代码](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Custom%20Packages.html#get-the-source-code)。

### kmod

构建 kmod 软件包时需要注意的关键点是必须指定特定的 Linux 内核。在配置阶段，构建系统会根据经验猜测你希望针对哪个内核构建。然而，如果 configure 找不到你的内核开发头文件，或者你想针对不同内核构建，则必须使用 *--with-linux* 和 *--with-linux-obj* 选项指定确切路径。

要构建 RPM 转换的 Debian 软件包：

```sh
$ cd zfs
$ ./configure --enable-systemd
$ make -j1 deb-utils deb-kmod
$ sudo apt-get install --fix-missing ./*.deb
```

从 openzfs-2.2 版本开始，可以按如下方式构建原生 Debian 软件包：

```sh
$ cd zfs
$ ./configure
$ make native-deb-utils native-deb-kmod
$ rm ../openzfs-zfs-dkms_*.deb
$ rm ../openzfs-zfs-dracut_*.deb  # 基于 deb 的系统通常使用 initramfs
$ sudo apt-get install --fix-missing ../*.deb
```

原生 Debian 软件包使用为 Debian 和 Ubuntu 预配置的路径构建。在 configure 阶段最好不要覆盖这些路径。可以通过指定环境变量 `KVERS`、`KSRC` 和 `KOBJ` 来指定安装在非默认位置的内核。

### DKMS

构建 RPM 转换的基于 deb 的 DKMS 和用户软件包可以按如下方式进行：

```sh
$ cd zfs
$ ./configure --enable-systemd
$ make -j1 deb-utils deb-dkms
$ sudo apt-get install --fix-missing ./*.deb
```

从 openzfs-2.2 版本开始，可以按如下方式构建原生基于 deb 的 DKMS 和用户软件包：

```sh
$ sudo apt-get install dh-dkms
$ cd zfs
$ ./configure
$ make native-deb-utils
$ rm ../openzfs-zfs-dracut_*.deb  # 基于 deb 的系统通常使用 initramfs
$ sudo apt-get install --fix-missing ../*.deb
```

## 获取源代码

### 发布 Tar 归档包

发布的 Tar 归档包是经过充分测试和已发布的最新 ZFS 版本。这是生产系统中使用的首选源代码位置。如果你想使用官方发布的 Tar 归档包，可以使用以下命令获取、准备源代码：

```sh
$ wget http://archive.zfsonlinux.org/downloads/zfsonlinux/zfs/zfs-x.y.z.tar.gz
$ tar -xzf zfs-x.y.z.tar.gz
```

### Git 主分支

Git *master* 分支是最新版本的软件，且可能包含那些未内置在已发布 Tar 归档包中的修复。这是打算修改 ZFS 的开发者的首选源代码位置。如果你想使用 git 版本，可以从 Github 克隆并按如下方式准备源代码：

```sh
$ git clone https://github.com/zfsonlinux/zfs.git
$ cd zfs
$ ./autogen.sh
```

源代码准备完成后，你需要决定构建哪种类型的软件包，然后跳转到上面的相应部分。请注意，并非所有平台都支持所有类型的软件包。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/zfs/kai-fa-zi-yuan/custompackages.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
