如何在 21 世纪编译 Linux 内核

您不必编译 Linux 内核,但您可以通过这个快速教程来编译。
131 位读者喜欢这篇文章。
and old computer and a new computer, representing migration to new software or hardware

Opensource.com

在计算机领域,内核是处理与硬件通信和一般系统协调的底层软件。除了内置于计算机主板中的一些初始固件之外,当您启动计算机时,内核会提供对硬盘、屏幕、键盘和网卡的感知。内核的工作还需要确保(或多或少)为每个组件提供相同的运行时间,以便您的图形、音频、文件系统和网络都能流畅运行,即使它们是同时运行的。

然而,对硬件支持的追求是持续不断的,因为发布的硬件越多,内核就必须在其代码中采用更多的东西,以使硬件按预期工作。很难获得准确的数字,但 Linux 内核无疑是硬件兼容性最好的内核之一。Linux 运行着无数的计算机和移动电话、用于业余爱好者和工业用途的片上系统 (SoC) 板、RAID 卡、缝纫机等等。

回到 20 世纪(甚至 21 世纪的早期),Linux 用户期望当他们购买非常新的硬件时,他们需要下载最新的内核源代码、编译并安装它,以便获得对该设备的支持,这并非不合理。但最近,您很难找到一个编译自己的内核的 Linux 用户,除非是为了娱乐或通过高度专业化的定制硬件获利。如今,通常不需要自己编译 Linux 内核。

以下是原因,以及在需要时如何编译内核的快速教程。

更新您现有的内核

无论您是拥有一台配备了花哨的新显卡或 WiFi 芯片组的全新笔记本电脑,还是刚刚带回家一台新打印机,您的操作系统(称为 GNU+Linux 或 Linux,Linux 也是内核的名称)都需要一个驱动程序来打开与新组件(显卡、WiFi 芯片、打印机或任何其他组件)的通信通道。有时,当您插入新设备并且您的计算机似乎识别了它时,这可能会具有欺骗性。但不要被它愚弄了。有时这正是您所需要的,但在其他时候,您的操作系统只是使用通用协议来探测已连接的设备。

例如,您的计算机可能能够识别您的新网络打印机,但有时这仅仅是因为打印机中的网卡被编程为向网络标识自己,以便它可以获得 DHCP 地址。这并不一定意味着您的计算机知道向打印机发送哪些指令来生成一页打印文本。事实上,您可能会认为计算机甚至不真正“知道”该设备是打印机;它可能只显示网络上有一个特定地址的设备,并且该设备用字符 p-r-i-n-t-e-r 系列标识自己。人类语言的约定对计算机来说毫无意义;它需要的是驱动程序。

内核开发人员、硬件制造商、支持技术人员和爱好者都知道,新的硬件不断发布。他们中的许多人贡献驱动程序,直接提交给内核开发团队以包含在 Linux 中。例如,Nvidia 显卡驱动程序通常被写入 Nouveau 内核模块,并且由于 Nvidia 显卡很常见,因此该代码通常包含在为通用用途分发的任何内核中(例如,当您下载 Fedora 或 Ubuntu 时获得的内核)。在 Nvidia 不太常见的情况下,例如在嵌入式系统中,通常会排除 Nouveau 模块。许多其他设备也存在类似的模块:打印机受益于 FoomaticCUPS,无线网卡具有 b43, ath9k, wl 模块等等。

发行版倾向于在其 Linux 内核构建中尽可能多地包含内容,因为他们希望您能够连接设备并立即开始使用它,而无需安装驱动程序。在大多数情况下,情况就是这样,尤其是现在许多设备供应商都在为其销售的硬件资助 Linux 驱动程序开发,并将这些驱动程序直接提交给内核团队以进行通用分发。

然而,有时,您运行的是六个月前安装的内核,并且使用了一个令人兴奋的新设备,该设备一周前才上市。在这种情况下,您的内核可能没有该设备的驱动程序。好消息是,通常情况下,该设备的驱动程序可能存在于最新版本的内核中,这意味着您只需更新您正在运行的内核即可。

通常,这是通过包管理器完成的。例如,在 RHEL、CentOS 和 Fedora 上

$ sudo dnf update kernel

在 Debian 和 Ubuntu 上,首先获取您当前的内核版本

$ uname -r
4.4.186

搜索更新的版本

$ sudo apt update
$ sudo apt search linux-image

安装您找到的最新版本。在本例中,最新的可用版本是 5.2.4

$ sudo apt install linux-image-5.2.4

内核升级后,您必须重新启动(除非您正在使用 kpatch 或 kgraft)。然后,如果您需要的设备驱动程序在最新的内核中,您的硬件将按预期工作。

安装内核模块

有时,发行版并不期望其用户经常使用某个设备(或者至少设备驱动程序不需要在 Linux 内核中)。Linux 对驱动程序采用模块化方法,因此发行版可以发布单独的驱动程序包,这些驱动程序包可以由内核加载,即使驱动程序本身没有编译到内核中。这很有用,但当驱动程序未包含在内核中但在启动期间需要时,或者当内核从模块化驱动程序下更新时,可能会变得复杂。第一个问题通过 initrd(初始 RAM 磁盘)解决,超出了本文的范围,第二个问题通过名为 kmod 的系统解决。

kmod 系统确保在内核更新时,与其一起安装的所有模块化驱动程序也会更新。如果您手动安装驱动程序,您将错过 kmod 提供的自动化功能,因此您应该尽可能选择 kmod 包。例如,虽然 Nvidia 驱动程序作为 Nouveau 驱动程序内置于内核中,但官方 Nvidia 驱动程序仅由 Nvidia 分发。您可以通过访问网站、下载 .run 文件并运行它提供的 shell 脚本来手动安装 Nvidia 品牌驱动程序,但是您必须在安装新内核后重复相同的过程,因为没有任何东西告诉您的包管理器您手动安装了内核驱动程序。由于 Nvidia 驱动您的图形,手动更新 Nvidia 驱动程序通常意味着您必须从终端执行更新,因为在没有功能正常的图形驱动程序的情况下,您没有图形。

Nvidia configuration application

但是,如果您将 Nvidia 驱动程序作为 kmod 包安装,则更新内核也会更新您的 Nvidia 驱动程序。在 Fedora 和相关发行版上

$ sudo dnf install kmod-nvidia

在 Debian 和相关发行版上

$ sudo apt update
$ sudo apt install nvidia-kernel-common nvidia-kernel-dkms nvidia-glx nvidia-xconfig nvidia-settings nvidia-vdpau-driver vdpau-va-driver

这只是一个示例,但如果您在现实生活中安装 Nvidia 驱动程序,您还必须将 Nouveau 驱动程序列入黑名单。请参阅您的发行版文档以了解最佳步骤。

下载并安装驱动程序

并非所有内容都包含在内核中,也并非所有其他内容都作为内核模块提供。在某些情况下,您必须下载由硬件供应商编写和捆绑的特殊驱动程序,而在其他情况下,您拥有驱动程序,但没有用于配置驱动程序选项的前端。

两个常见的例子是 HP 打印机和 Wacom 绘图板。如果您获得 HP 打印机,您可能拥有可以与您的打印机通信的通用驱动程序。您甚至可能能够打印。但是通用驱动程序可能无法提供特定于您型号的专用选项,例如双面打印、分页、纸盒选择等等。HPLIP(HP Linux 成像和打印系统)提供了管理作业、调整打印选项、在适用的情况下选择纸盒等选项。

HPLIP 通常捆绑在包管理器中;只需搜索“hplip”即可。

HPLIP in action

同样,Wacom 平板电脑(数字艺术家领先的绘图板)的驱动程序通常包含在您的内核中,但微调设置的选项(例如压力灵敏度和按钮功能)只能通过 GNOME 默认包含的图形控制面板访问,但在 KDE 上可以作为额外的包 kde-config-tablet 安装。

可能有一些边缘情况,内核中没有驱动程序,但提供驱动程序模块的 kmod 版本作为 RPM 或 DEB 文件,您可以下载并通过包管理器安装。

补丁和编译您自己的内核

即使在 21 世纪这个未来的乌托邦中,仍然有一些供应商对开源的理解不足以提供可安装的驱动程序。有时,这些公司提供驱动程序的源代码,但希望您下载代码、修补内核、编译并手动安装。

这种分发模型与在 kmod 系统之外安装打包驱动程序具有相同的缺点:内核更新会破坏驱动程序,因为它每次将内核换成新内核时都必须手动重新集成到您的内核中。

令人高兴的是,这种情况已经变得很少见,因为 Linux 内核团队在强烈呼吁公司与他们沟通方面做得非常出色,并且因为公司最终接受了开源不会在短期内消失。但是,仍然有一些新颖或高度专业化的设备只提供内核补丁。

官方而言,对于您应该如何编译内核以使您的包管理器参与升级系统的这个重要部分,存在特定于发行版的偏好。包管理器太多,无法一一介绍;例如,以下是当您在 Fedora 上使用 rpmdev 或在 Debian 上使用 build-essentialdevscripts 等工具时幕后发生的事情。

首先,像往常一样,找出您正在运行的内核版本

$ uname -r

在大多数情况下,如果您尚未升级内核,则升级内核是安全的。毕竟,您的问题很可能在最新版本中得到解决。如果您尝试过但没有奏效,那么您应该下载您正在运行的内核的源代码。大多数发行版都为此提供了一个特殊的命令,但要手动执行此操作,您可以在 kernel.org 上找到源代码。

您还必须下载内核所需的任何补丁。有时,这些补丁特定于内核版本,因此请仔细选择。

传统上,或者至少在人们经常编译自己的内核时是这样,将源代码和补丁放在 /usr/src/linux 中。

根据需要解压内核源代码和补丁文件

$ cd /usr/src/linux
$ bzip2 --decompress linux-5.2.4.tar.bz2
$ cd  linux-5.2.4
$ bzip2 -d ../patch*bz2

补丁文件可能包含有关如何打补丁的说明,但通常它们被设计为从您的树的顶层执行

$ patch -p1 < patch*example.patch

一旦内核代码被修补,您可以使用旧的配置来准备修补后的内核配置

$ make oldconfig

make oldconfig 命令有两个目的:它继承您当前内核的配置,并允许您配置补丁引入的新选项。

您可能需要运行 make menuconfig 命令,该命令启动一个基于 ncurses 的菜单驱动的列表,其中包含新内核的可能选项。菜单可能令人眼花缭乱,但由于它以您的旧配置为基础开始,您可以浏览菜单并禁用您知道您没有并且不希望需要的硬件模块。或者,如果您知道您拥有某些硬件并且看到它未包含在您当前的配置中,您可以选择构建它,无论是作为模块还是直接构建到内核中。从理论上讲,这没有必要,因为据推测,您当前的内核对您运行良好,只是缺少补丁,并且您应用的补丁可能已激活最初提示您修补内核的任何设备所需的所有必要选项。

接下来,编译内核及其模块

$ make bzImage
$ make modules

这会为您留下一个名为 vmlinuz 的文件,它是可引导内核的压缩版本。保存您的旧版本并将新版本放在您的 /boot 目录中

$ sudo mv /boot/vmlinuz /boot/vmlinuz.nopatch
$ sudo cat arch/x86_64/boot/bzImage > /boot/vmlinuz
$ sudo mv /boot/System.map /boot/System.map.stock
$ sudo cp System.map /boot/System.map

到目前为止,您已经修补并构建了内核及其模块,您已经安装了内核,但您尚未安装任何模块。这是最后的构建步骤

$ sudo make modules_install

新内核已就位,其模块已安装。

最后一步是更新您的引导加载程序,以便在内核之前加载的计算机部分知道在哪里找到 Linux。GRUB 引导加载程序使此过程相对简单

$ sudo grub2-mkconfig

真实世界的编译

当然,现在没有人运行这些手动命令了。相反,请参阅您的发行版,以获取有关使用您的发行版维护者使用的开发人员工具集修改内核的说明。此工具集可能会创建一个新的可安装软件包,其中包含所有已合并的补丁,提醒包管理器进行升级,并为您更新引导加载程序。

内核

操作系统和内核是神秘的东西,但要理解它们构建在哪些组件之上并不需要太多。下次您获得一个似乎无法在 Linux 上运行的技术组件时,请深吸一口气,调查驱动程序的可用性,并选择阻力最小的路径。Linux 比以往任何时候都更容易——这包括内核。

标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。他曾在电影和计算机行业工作,而且经常同时从事这两个行业。

7 条评论

我想阅读有关内核开发的更新

您可以做到!内核是开源开发的,因此您可以关注其邮件列表或订阅 lwn.net

回复 ,作者 Peterscott (未验证)

至少在 Fedora 中,新内核出现得如此频繁,以至于自己编译内核毫无意义。最好做一些有用的事情,比如洗衣服。

我明白了。但是,仅仅因为有新内核可用,并不总是意味着它们包含了人们需要编译到其中的内容。肯定有人仍然自己编译内核,即使主要用于边缘情况硬件。这是一项有用的技能!

回复 ,作者 Greg P

如果说我需要并使用过任何技能,那就是知道当最新的内核破坏我系统上的某些东西时如何返回到以前的内核。

回复 ,作者 sethkenlon

好文章!我真的需要阅读有关 DKMS 的内容。

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.