第 12 章. Linux 二进制兼容性

12.1. 摘要

FreeBSD 提供了与 Linux® 的**可选**二进制兼容性,通常称为 Linuxulator,允许用户安装和运行未经修改的 Linux 二进制文件。它适用于 x86(32 位和 64 位)和 AArch64 架构。一些 Linux 特定的操作系统功能尚不支持;这主要发生在特定于硬件或与系统管理相关的功能上,例如 cgroups 或命名空间。

在阅读本章之前,您应该

阅读完本章后,您将了解

  • 如何在 FreeBSD 系统上启用 Linux 二进制兼容性。

  • 如何安装额外的 Linux 共享库。

  • 如何在 FreeBSD 系统上安装 Linux 应用程序。

  • FreeBSD 中 Linux 兼容性的实现细节。

12.2. 配置 Linux 二进制兼容性

默认情况下,linux(4) 二进制兼容性未启用。

要在启动时启用 Linux ABI,请执行以下命令

# sysrc linux_enable="YES"

启用后,可以通过执行以下命令在不重启的情况下启动它

# service linux start

这足以使静态链接的 Linux 二进制文件工作。

Linux 服务将加载必要的内核模块,并在 /compat/linux 下挂载 Linux 应用程序预期的文件系统。它们可以像原生 FreeBSD 二进制文件一样启动;它们的行为几乎与原生进程完全相同,并且可以使用通常的方式进行跟踪和调试。

可以通过执行以下命令检查 /compat/linux 的当前内容

# ls -l /compat/linux/

输出应类似于以下内容

total 1
dr-xr-xr-x  13 root  wheel  512 Apr 11 19:12 dev
dr-xr-xr-x   1 root  wheel    0 Apr 11 21:03 proc
dr-xr-xr-x   1 root  wheel    0 Apr 11 21:03 sys

12.3. Linux 用户空间

Linux 软件需要不仅仅是 ABI 才能工作。为了运行 Linux 软件,必须首先安装 Linux 用户空间。

如果只想运行 Ports 树中已包含的一些软件,可以通过包管理器安装,并且 pkg(8) 将自动设置所需的 Linux 用户空间。

例如,要安装 Sublime Text 4 及其依赖的所有 Linux 库,请运行以下命令

# pkg install linux-sublime-text4

12.3.1. 来自 FreeBSD 包的 Rocky Linux 基础系统

要安装 Rocky Linux 9 用户空间,请执行以下命令

# pkg install linux_base-rl9

emulators/linux_base-rl9 将从 Rocky Linux 9 派生的基础系统放置到 /compat/linux 中。

安装软件包后,可以通过运行以下命令验证 /compat/linux 的内容,以检查是否已安装 Rocky Linux 用户空间

# ls -l /compat/linux/

输出应类似于以下内容

total 36
drwxr-xr-x   2 root wheel  512 Oct  9 17:28 afs
lrwxr-xr-x   1 root wheel    7 May 16  2022 bin -> usr/bin
drwxr-xr-x   3 root wheel  512 Oct  9 17:28 dev
drwxr-xr-x  24 root wheel 1536 Oct  9 17:28 etc
lrwxr-xr-x   1 root wheel    7 May 16  2022 lib -> usr/lib
lrwxr-xr-x   1 root wheel    9 May 16  2022 lib64 -> usr/lib64
drwxr-xr-x   2 root wheel  512 Oct  9 17:28 opt
drwxr-xr-x   2 root wheel  512 Oct  9 17:28 proc
lrwxr-xr-x   1 root wheel    8 Oct  1 03:11 run -> /var/run
lrwxr-xr-x   1 root wheel    8 May 16  2022 sbin -> usr/sbin
drwxr-xr-x   2 root wheel  512 Oct  9 17:28 srv
drwxr-xr-x   2 root wheel  512 Oct  9 17:28 sys
drwxr-xr-x   8 root wheel  512 Oct  9 17:28 usr
drwxr-xr-x  16 root wheel  512 Oct  9 17:28 var

12.3.2. 来自 FreeBSD 包的 CentOS 基础系统

由于上游项目的弃用,emulators/linux_base-c7 已被弃用。这意味着 emulators/linux_base-c7 将不会收到安全更新。除非需要 32 位兼容性,否则建议使用 Rocky Linux 基础系统

要安装 CentOS 用户空间,请执行以下命令

# pkg install linux_base-c7

emulators/linux_base-c7 将从 CentOS 7 派生的基础系统放置到 /compat/linux 中。

安装软件包后,可以通过运行以下命令验证 /compat/linux 的内容,以检查是否已安装 CentOS 用户空间

# ls -l /compat/linux/

输出应类似于以下内容

total 30
lrwxr-xr-x   1 root  wheel    7 Apr 11  2018 bin -> usr/bin
drwxr-xr-x  13 root  wheel  512 Apr 11 21:10 dev
drwxr-xr-x  25 root  wheel   64 Apr 11 21:10 etc
lrwxr-xr-x   1 root  wheel    7 Apr 11  2018 lib -> usr/lib
lrwxr-xr-x   1 root  wheel    9 Apr 11  2018 lib64 -> usr/lib64
drwxr-xr-x   2 root  wheel    2 Apr 11 21:10 opt
dr-xr-xr-x   1 root  wheel    0 Apr 11 21:25 proc
lrwxr-xr-x   1 root  wheel    8 Feb 18 02:10 run -> /var/run
lrwxr-xr-x   1 root  wheel    8 Apr 11  2018 sbin -> usr/sbin
drwxr-xr-x   2 root  wheel    2 Apr 11 21:10 srv
dr-xr-xr-x   1 root  wheel    0 Apr 11 21:25 sys
drwxr-xr-x   8 root  wheel    9 Apr 11 21:10 usr
drwxr-xr-x  16 root  wheel   17 Apr 11 21:10 var

12.3.3. 使用 debootstrap 的 Debian/Ubuntu 基础系统

提供 Linux 共享库的另一种方法是使用 sysutils/debootstrap。这具有提供完整 Debian 或 Ubuntu 发行版的优势。

要安装 debootstrap,请执行以下命令

# pkg install debootstrap

debootstrap(8) 需要启用 linux(4) ABI。启用后,请执行以下命令以在 /compat/ubuntu 中安装 Ubuntu 或 Debian

# debootstrap focal /compat/ubuntu

虽然从技术上讲可以安装到 /compat/linux 中,但由于可能与基于 CentOS 的软件包发生冲突,因此不建议这样做。相反,从发行版或版本名称派生目录名称,例如 /compat/ubuntu

输出应类似于以下内容

I: Retrieving InRelease
I: Checking Release signature
I: Valid Release signature (key id F6ECB3762474EDA9D21B7022871920D1991BC93C)
I: Retrieving Packages
I: Validating Packages
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
I: Checking component main on http://archive.ubuntu.com/ubuntu...
[...]
I: Configuring console-setup...
I: Configuring kbd...
I: Configuring ubuntu-minimal...
I: Configuring libc-bin...
I: Configuring ca-certificates...
I: Base system installed successfully.

然后在 /etc/fstab 中设置挂载点。

如果应共享主目录的内容并能够运行 X11 应用程序,则应使用 nullfs(5) 进行循环回送,将 /home/tmp 挂载到 linux 兼容区域。

以下示例可以添加到 /etc/fstab

# Device        Mountpoint              FStype          Options                      Dump    Pass#
devfs           /compat/ubuntu/dev      devfs           rw,late                      0       0
tmpfs           /compat/ubuntu/dev/shm  tmpfs           rw,late,size=1g,mode=1777    0       0
fdescfs         /compat/ubuntu/dev/fd   fdescfs         rw,late,linrdlnk             0       0
linprocfs       /compat/ubuntu/proc     linprocfs       rw,late                      0       0
linsysfs        /compat/ubuntu/sys      linsysfs        rw,late                      0       0
/tmp            /compat/ubuntu/tmp      nullfs          rw,late                      0       0
/home           /compat/ubuntu/home     nullfs          rw,late                      0       0

然后执行 mount(8)

# mount -al

要使用 chroot(8) 访问系统,请执行以下命令

# chroot /compat/ubuntu /bin/bash

然后可以执行 uname(1) 以检查 Linux 环境

# uname -s -r -m

输出应类似于以下内容

Linux 3.17.0 x86_64

进入 chroot 后,系统行为与正常的 Ubuntu 安装相同。虽然 systemd 不起作用,但 service(8) 命令照常工作。

要添加默认情况下缺少的软件包存储库,请编辑文件 /compat/ubuntu/etc/apt/sources.list

对于 amd64,可以使用以下示例

deb http://archive.ubuntu.com/ubuntu focal main universe restricted multiverse
deb http://security.ubuntu.com/ubuntu/ focal-security universe multiverse restricted main
deb http://archive.ubuntu.com/ubuntu focal-backports universe multiverse restricted main
deb http://archive.ubuntu.com/ubuntu focal-updates universe multiverse restricted main

对于 arm64,可以使用以下示例

deb http://ports.ubuntu.com/ubuntu-ports bionic main universe restricted multiverse

12.4. 高级主题

所有与 Linux 相关的 sysctl(8) 旋钮的列表可以在 linux(4) 中找到。

某些应用程序需要挂载特定的文件系统。

这通常由 /etc/rc.d/linux 脚本处理,但可以通过执行以下命令在启动时禁用

sysrc linux_mounts_enable="NO"

rc 脚本挂载的文件系统对 chroot 或 jail 中的 Linux 进程不起作用;如果需要,请在 /etc/fstab 中配置它们

devfs      /compat/linux/dev      devfs      rw,late                    0  0
tmpfs      /compat/linux/dev/shm  tmpfs      rw,late,size=1g,mode=1777  0  0
fdescfs    /compat/linux/dev/fd   fdescfs    rw,late,linrdlnk           0  0
linprocfs  /compat/linux/proc     linprocfs  rw,late                    0  0
linsysfs   /compat/linux/sys      linsysfs   rw,late                    0  0

由于 Linux 二进制兼容性层已获得对运行 32 位和 64 位 Linux 二进制文件的支持,因此不再可能将模拟功能静态链接到自定义内核中。

12.4.1. 手动安装其他库

对于使用 debootstrap(8) 创建的基础系统子目录,请改用上述说明。

如果在配置 Linux 二进制兼容性后,Linux 应用程序抱怨缺少共享库,请确定 Linux 二进制文件需要哪些共享库并手动安装它们。

在使用相同 CPU 架构的 Linux 系统中,可以使用 ldd 确定应用程序需要哪些共享库。

例如,要检查 linuxdoom 需要哪些共享库,请在已安装 Doom 的 Linux 系统中运行以下命令

% ldd linuxdoom

输出应类似于以下内容

libXt.so.3 (DLL Jump 3.1) => /usr/X11/lib/libXt.so.3.1.0
libX11.so.3 (DLL Jump 3.1) => /usr/X11/lib/libX11.so.3.1.0
libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29

然后,将输出最后一列中的所有文件从 Linux 系统复制到 FreeBSD 系统上的 /compat/linux 中。复制完成后,创建指向第一列中名称的符号链接。

此示例将在 FreeBSD 系统上生成以下文件

/compat/linux/usr/X11/lib/libXt.so.3.1.0
/compat/linux/usr/X11/lib/libXt.so.3 -> libXt.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3 -> libX11.so.3.1.0
/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29

如果 Linux 共享库已存在且主修订号与 ldd 输出的第一列匹配,则无需将其复制到最后一列中命名的文件,因为现有库应该可以工作。不过,如果它是较新版本,建议复制共享库。可以删除旧的库,只要符号链接指向新的库即可。

例如,这些库已存在于 FreeBSD 系统上

/compat/linux/lib/libc.so.4.6.27
/compat/linux/lib/libc.so.4 -> libc.so.4.6.27

并且 ldd 指示二进制文件需要较新版本

libc.so.4 (DLL Jump 4.5pl26) -> libc.so.4.6.29

由于现有库在最后一位数字上仅落后一两个版本,因此程序仍然可以使用稍旧的版本。但是,用较新版本替换现有的 libc.so 是安全的

/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29

通常,只需要在 FreeBSD 上首次安装 Linux 程序时查找 Linux 二进制文件依赖的共享库。一段时间后,系统上将有一组足够的 Linux 共享库,能够在无需任何额外工作的情况下运行新安装的 Linux 二进制文件。

12.4.2. 标记 Linux ELF 二进制文件

FreeBSD 内核使用多种方法来确定要执行的二进制文件是否是 Linux 二进制文件:它检查 ELF 文件头中的品牌,查找已知的 ELF 解释器路径并检查 ELF 注记;最后,默认情况下,未标记的 ELF 可执行文件被假定为 Linux 可执行文件。

如果所有这些方法都失败,则尝试执行二进制文件可能会导致错误消息

% ./my-linux-elf-binary

输出应类似于以下内容

ELF binary type not known
Abort

为了帮助 FreeBSD 内核区分 FreeBSD ELF 二进制文件和 Linux 二进制文件,请使用 brandelf(1)

% brandelf -t Linux my-linux-elf-binary

12.4.3. 安装基于 Linux RPM 的应用程序

要安装基于 Linux RPM 的应用程序,首先安装 archivers/rpm4 软件包或端口。安装完成后,root 可以使用此命令安装 .rpm

# cd /compat/linux
# rpm2cpio < /path/to/linux.archive.rpm | cpio -id

如有必要,请使用 brandelf 标记已安装的 ELF 二进制文件。请注意,这将阻止干净卸载。

12.4.4. 配置主机名解析器

如果 DNS 不工作或出现此错误

resolv+: "bind" is an invalid keyword resolv+:
"hosts" is an invalid keyword

请如下配置 /compat/linux/etc/host.conf

order hosts, bind
multi on

这指定首先搜索 /etc/hosts,然后搜索 DNS。当 /compat/linux/etc/host.conf 不存在时,Linux 应用程序使用主机系统中的 /etc/host.conf,但它们会报错,因为该文件在 FreeBSD 中不存在。如果未使用 /etc/resolv.conf 配置名称服务器,请删除 bind

12.4.5. 其他

有关 Linux® 二进制兼容性如何工作的更多信息,请参阅文章 FreeBSD 中的 Linux 模拟


最后修改时间:2024 年 10 月 13 日,作者 Fernando Apesteguía