第 12 章 Linux 二进制兼容性

如果发现翻译错误,请直接 发起PR修改

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 服务将加载 Linux 应用程序所需的内核模块并挂载文件系统,这些文件系统位于 /compat/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 软件包中获取的 CentOS 基本系统

要安装 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.2. 使用 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 脚本挂载的文件系统在 chroots 或 jails 中的 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

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

例如,这些库已经存在于 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 包或port。安装完成后,root 用户可以使用以下命令来安装 .rpm 文件:

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

如果需要的话,对已安装的 ELF 二进制文件进行 brandelf 处理。请注意,这将阻止干净卸载。

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 中该文件不存在。如果没有配置名称服务器,请删除 bind,使用 /etc/resolv.conf

12.4.5. 杂项

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


上次修改时间: September 18, 2024 by fiercex