Linux教程

Linux 之旅 24:内核编译

本文主要是介绍Linux 之旅 24:内核编译,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Linux 之旅 24:内核编译

image-20210917151509156

图源:pexels

认识内核与获取源码

什么是系统内核

内核(Kernel)是整个操作系统的最底层,负责所有硬件的驱动,以及提供系统所需的内核功能。

所有需要让计算机完成的功能,都需要内核支持才行。

内核的本质是一个大型程序,可以在编译后加载到内存中执行,进而加载各种驱动和模块,驱动主机的相关硬件,然后对系统中的其它软件提供相应的功能。

为了节省空间,编译后的内核通常会被压缩成一个内核文件,使用的时候再被解压到内存中。一个Linux主机上可以有多个内核文件,可以在启动的时候选择其中一个用于加载系统。当然也可以通过grub2等boot loader进行多重引导。

前面说过了,内核需要编译后才能使用(执行),而编译自然需要相应的源代码,一般称为内核源码。

默认情况下我们安装的Linux发行版是不会附带内核源码的,如果要安装源码就要去Linux发行版的官网下载安装对应的内核SRMP文件。而如果想安装其它版本的内核,可以直接从网上下载相应的内核源码Tarball,解压后进行内核编译,然后通过grub2进行引导就可以使用了。

更新内核的目的

通常来说,我们不太需要对内核进行频繁编译,而且一般来说Linux发行版自带的编译好的内核就能满足我们日常的需要。只有当出现以下几种情况的时候你可能才需要编译内核:

  • 新功能的需求

    内核是频繁更新的,随着更新会逐渐加入一些新功能和特性,如果你想使用新版本内核加入的功能,或者是你有新的硬件要使用,但新硬件无法被旧版本的内核识别或加载,那你就可能需要进行内核编译。

  • 需要精简内核

    Linux发行版附带的默认内核是针对大部分人的使用情况来设置的,所以在极个别特殊情况下可能会显得很“臃肿”,比如你要安装的目标硬件是嵌入式设备,硬件水平有限,需要节省内存或者磁盘,那你可能需要重新编译内核,以去除不需要的功能来精简内核。

  • 与硬件搭配的稳定性

    Linux发行版附带的默认内核大多数是针对Intel的CPU设置的,如果你的CPU是其它型号,比如AMD或ARM,有可能会运行的不是很完美,此时你可以对内核源码的设置进行调整,专门对你的特异CPU进行优化后重新编译内核。

内核版本

如要要查看当前使用的内核版本:

[icexmoon@xyz ~]$ uname -r
3.10.0-1160.el7.x86_64

CentOS 7使用3.10.x作为长期维护版本,所以升级内核的话最好使用3.10.x版本的内核,比如3.10.89。

当然你也可以不遵守上边的限制,直接使用最新的5.x.x版本内核,但是跨越大版本升级内核可能出现一些无法解决的问题。

获取内核源码

通过Linux发行版官网获取

如果要获取当前使用的Linux发行版的默认内核对应的源码,最好的方式是通过其官网获取:

CentOS官网提供源码的页面是:https://vault.centos.org/。

寻找对应的CentOS版本(我这里是7.9.2009),然后查找到updates目录,然后往下找.src.rpm文件,最终我找到的是这个页面:https://vault.centos.org/7.9.2009/updates/Source/SPackages/:

image-20210917155139616

有多个SRPM文件,其中kernel.xxx就是内核的SRMP包,kernel-3.10.0-1160.el7.src.rpm应该就是我当前使用的内核对应的SRPM包,其它类似kernel-3.10.0-1160.42.2.el7.src.rpm应该是小版本更新后的SRPM包。

下载SRPM包后进行解包,就能获取相应的内核源码。

获取最新的内核源码

Linux内核一直都是由Linux创始人Linus所属的团队在负责开发维护,其发布内核的官网是:

  • https://www.kernel.org/

image-20210917155911170

具体提供所有Linux内核源码的地址是:https://mirrors.edge.kernel.org/pub/linux/kernel/

如果访问速度不快,可以使用其它镜像站,这里找到一个中科大的Linux用户协会网站:

  • https://lug.ustc.edu.cn/

image-20210917161613350

该网站提供Linux相关资源的镜像站,内核的下载网址是:

  • https://mirrors.ustc.edu.cn/kernel.org/linux/kernel/

除了内核,还有其它很多Linux资源镜像。

使用patch升级

之前在在Linux 之旅 21:编译安装软件中介绍过怎么使用.patch文件来升级软件。如果你已经有某个版本的内核源码了,也可以使用这种方式进行升级,不过需要注意的是需要按照版本顺序依次使用.path文件升级,比如你当前内核版本是5.8.1,使用patch-5.8.2可以升级到5.8.2内核,再使用patch-5.8.3就可以升级到5.8.3版本的内核,以此类推。

内核源码的解压、安装和查看

先下载需要的源码,这里我选择linux-3.10.99版本的源码:

[icexmoon@xyz tmp]$ wget https://mirrors.edge.kernel.org/pub/linux/kernel/v3.x/linux-3.10.99.tar.xz
--2021-09-17 16:33:01--  https://mirrors.edge.kernel.org/pub/linux/kernel/v3.x/linux-3.10.99.tar.xz
正在解析主机 mirrors.edge.kernel.org (mirrors.edge.kernel.org)... 2604:1380:3000:1500::1, 147.75.95.133
正在连接 mirrors.edge.kernel.org (mirrors.edge.kernel.org)|2604:1380:3000:1500::1|:443... 失败:连接超时。
正在连接 mirrors.edge.kernel.org (mirrors.edge.kernel.org)|147.75.95.133|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:73312148 (70M) [application/x-xz]
正在保存至: “linux-3.10.99.tar.xz”

100%[===========================================================================================>] 73,312,148   153KB/s 用时 6m 51s

2021-09-17 16:42:00 (174 KB/s) - 已保存 “linux-3.10.99.tar.xz” [73312148/73312148])
  • 速度比较慢,原因是wget会先尝试通过IPV6进行连接,如果服务器不支持就一直要等待,建议使用wget -4指定通过IPV4进行连接,建立连接的所读会快得多。
  • 官方镜像下载速度会很慢,建议使用上边提供的国内镜像,能慢速下载。

一般来说,内核源码应该安装到/usr/src/kernels/目录:

[root@xyz tmp]# tar -Jxvf linux-3.10.99.tar.xz -C /usr/src/kernels/
...省略
linux-3.10.99/virt/kvm/iodev.h
linux-3.10.99/virt/kvm/iommu.c
linux-3.10.99/virt/kvm/irq_comm.c
linux-3.10.99/virt/kvm/irqchip.c
linux-3.10.99/virt/kvm/kvm_main.c
[root@xyz tmp]# du -sh /usr/src/kernels/linux-3.10.99/
566M    /usr/src/kernels/linux-3.10.99/

居然解压出来要566M,恐怖如斯。

解压出的内核源码包含以下目录:

[root@xyz tmp]# ll /usr/src/kernels/linux-3.10.99/ | grep '^d'
drwxrwxr-x.  32 root root   4096 3月   4 2016 arch
drwxrwxr-x.   3 root root   4096 3月   4 2016 block
drwxrwxr-x.   4 root root   4096 3月   4 2016 crypto
drwxrwxr-x. 100 root root   8192 3月   4 2016 Documentation
drwxrwxr-x. 112 root root   4096 3月   4 2016 drivers
drwxrwxr-x.  36 root root   4096 3月   4 2016 firmware
drwxrwxr-x.  73 root root   4096 3月   4 2016 fs
drwxrwxr-x.  26 root root   4096 3月   4 2016 include
drwxrwxr-x.   2 root root    254 3月   4 2016 init
drwxrwxr-x.   2 root root    256 3月   4 2016 ipc
drwxrwxr-x.  11 root root   4096 3月   4 2016 kernel
drwxrwxr-x.   9 root root   8192 3月   4 2016 lib
drwxrwxr-x.   2 root root   4096 3月   4 2016 mm
drwxrwxr-x.  55 root root   4096 3月   4 2016 net
drwxrwxr-x.  12 root root    186 3月   4 2016 samples
drwxrwxr-x.  13 root root   4096 3月   4 2016 scripts
drwxrwxr-x.   9 root root    268 3月   4 2016 security
drwxrwxr-x.  22 root root   4096 3月   4 2016 sound
drwxrwxr-x.  17 root root    215 3月   4 2016 tools
drwxrwxr-x.   2 root root    102 3月   4 2016 usr
drwxrwxr-x.   3 root root     17 3月   4 2016 virt

这些目录的用途为:

  • arch :與硬體平台有關的項目,大部分指的是 CPU 的類別,例如 x86, x86_64, Xen 虛擬支援等;
  • block :與區塊裝置較相關的設定資料,區塊資料通常指的是大量儲存媒體!還包括類似 ext3 等檔案系統的支援是否允許等。
  • crypto :核心所支援的加密的技術,例如 md5 或者是 des 等等;
  • Documentation :與核心有關的一堆說明文件,若對核心有極大的興趣,要瞧瞧這裡!
  • drivers :一些硬體的驅動程式,例如顯示卡、網路卡、PCI 相關硬體等等;
  • firmware :一些舊式硬體的微指令碼 (韌體) 資料;
  • fs :核心所支援的 filesystems ,例如 vfat, reiserfs, nfs 等等;
  • include :一些可讓其他程序呼叫的標頭 (header) 定義資料;
  • init :一些核心初始化的定義功能,包括掛載與 init 程式的呼叫等;
  • ipc :定義 Linux 作業系統內各程序的溝通;
  • kernel :定義核心的程序、核心狀態、執行緒、程序的排程 (schedule)、程序的訊號 (signle) 等
  • lib :一些函式庫;
  • mm :與記憶體單元有關的各項資料,包括 swap 與虛擬記憶體等;
  • net :與網路有關的各項協定資料,還有防火牆模組 (net/ipv4/netfilter/*) 等等;
  • security :包括 selinux 等在內的安全性設定;
  • sound :與音效有關的各項模組;
  • virt :與虛擬化機器有關的資訊,目前核心支援的是 KVM (Kernel base Virtual Machine)

摘抄自鸟哥的Linux私房菜

内核编译前的预处理与功能选择

清理源码环境

在编译之前应当清理源码目录,将可能存在的之前编译产生配置文件和目标文件(object file)清除:

[root@xyz tmp]# cd /usr/src/kernels/linux-3.10.99/
[root@xyz linux-3.10.99]# make mrproper

需要注意的是,make mrproper命令会将内核功能选择文件一并删除,如果仅需要清理之前编译残留的文件,可以:

[root@xyz linux-3.10.99]# make clean

make clean仅会删除编译产生的中间文件,不会删除相关配置文件。

选择内核功能

在开始编译内核前,需要先选择内核功能,即为内核设定好哪些功能直接编译进内核,哪些功能是编译成模块外挂,哪些功能是完全不需要的。

具体可以通过以下几种方式进行设置:

  • make menuconfig

    命令行下以纯文本的方式进行设置。

  • make oldconfig

    使用已存在的./.config文件作为默认设置,在此基础上仅将新功能列出让用户选择。

  • make xconfig

    通过Qt图形接口实现的界面进行设置,比如支持Qt图形接口的KDE下就可以使用此功能进行设置。

  • make gconfig

    通过Gtk图形接口实现的界面进行设置,比如支持Gtk图形接口的GNOME就可以使用此功能进行设置。

  • make config

    最原始的设置方式,选择错误后将无法修改。

通过既有设置来完成内核功能选择

这里以默认内核的配置文件作为参考来设置新内核的功能:

[root@xyz linux-3.10.99]# ll /boot/config-3.10.0-1160.el7.x86_64
-rw-r--r--. 1 root root 153591 10月 20 2020 /boot/config-3.10.0-1160.el7.x86_64
[root@xyz linux-3.10.99]# cp /boot/config-3.10.0-1160.el7.x86_64 .config
[root@xyz linux-3.10.99]# ll .config
-rw-r--r--. 1 root root 153591 9月  17 17:13 .config

下面进行内核选择:

[root@xyz linux-3.10.99]# make menuconfig

会出现这样的界面:

image-20210917172559477

有点像是BIOS的设置界面。

操作方式很简单,上边是具体的设置项,下边是菜单,选中不同的菜单项有不同的功能:

  • Select:当选中该菜单项时:
    • 按下Enter会进入当前设置项(有子设置项的菜单尾部会有-->符号)
    • 按下Space(空格)会修改当前配置项(头部有[]<>标识的才能修改)
  • Exit:选中时按下Enter会返回上一级菜单,如果已经是顶部菜单,将退出设置程序。
  • Help:选中时按下Enter会显示选中设置项的帮助信息。
  • Save:选中时按下Enter会保留当前的设置到配置文件。
  • Load:从配置文件加载内核设置。

内核功能项的设置值主要分以下几种:

  • -*-:默认编译到内核,无法修改。
  • [*]:编译到内核。
  • [M]:编译到内核模块。
  • [ ]:不使用该功能。

内核功能选择

General setup

这部分设置是与Linux最相关的程序交互、内核版本说明、是否使用开发中的程序代码等相关的。

image-20210917174327863

这里仅做了上面的修改,其余均保持默认值。

其中Local versionAutomatically append version...的用途是可以在Linux内核版本后添加上一段自定义字符,比如上边设置后最终编译出的内核版本显示的时候就会显示3.10.99icexmoon之类的字样。

Kernel compression mode是内核编译后的压缩模式,使用Bzip2可以让内核拥有较高的压缩比。

Kernel .config support可以让内核的配置文件直接写入内核文件。

其余相关配置的说明可以阅读鸟哥的Linux私房菜

Enable loadable module support

这里是内核加载模块的相关设置,如果内核要能加载模块,该功能必须写入内核。

image-20210917175334640

这里仅增加了一个Forced module unloading功能,该功能可以让内核强制卸载模块。

Enable the block layer

其下的自配置项Patition Types涉及分区的相关功能:

image-20210917175757308

image-20210917175857833

这里均保持默认值。

子配置项I/O scheduler可以设置I/O调度算法:

image-20210917180032146

这里建议设置为Deadline

Processor type and features

这一部分设置包括CPU的类型与功能选择。

子选项Linux guest support提供Linux虚拟化相关功能:

image-20210917182417626

这里保持默认选项。

选项Preemption Model可以调整内核抢占模式:

image-20210917182731079

具体分为三种:

  • No Forced Preemption (Server)
  • Voluntary Kernel Preemption (Desktop)
  • Preemptible Kernel (Low-Latency Desktop)

如果Linux主机的用途是服务器,可以修改选项为No Forced Preemption (Server)

内核抢占模式的更多内容可以阅读Linux Preemption模式

选项Timer frequency可以调整CPU的时钟频率,时钟频率会影响CPU的调度和执行,如果Linux主机用于服务器,可以适当调低时钟频率,比如300 HZ。这里使用默认值1000HZ:

image-20210917183211229

Power management and ACPI options

这里是电源管理的相关功能。如果硬件支持,可以通过这里的设置降低系统的能耗。

子选项CPU Frequency scaling中可以设置CPU频率脉冲相关的功能:

image-20210917184251955

其中Default CPUFreq governor可以设置CPU频率调节模式,这里设置为ondemand

更多的CPU频率调节模式可以阅读cpufreq 五种模式

Bus options (PCI etc.)

这里是总线相关的功能。

image-20210917185209836

这里保留默认值,其中PCI Stub driver选项为虚拟化需要的功能。

Executable file formats / Emulations

这里是文件格式相关的功能。

image-20210917185540417

虽然现在都是64位系统环境,但可以打开IA32 a.out supportx32 ABI for 64-bit mode,以兼容32位程序的运行。

Networking support

这里是网络相关的选项,包括防火墙等。

子选项Networking options中包含防火墙的功能:

image-20210917190212079

image-20210917190344646

image-20210917190509641

在这里打开Transparent proxying support功能。

其它选项均保持默认值,如果想了解更多相关功能说明,请阅读鸟哥的Linux私房菜

Device Drivers

这里是驱动相关的设置。这里不做修改,直接使用默认值。

image-20210917191139814

File systems

这里是文件系统相关的设置。

image-20210917191457247

CentOS 7默认是不支持ext2ext3的,这里开启。

image-20210917191840128

增加一个xfs realtime subvolume support,该功能可以支持“事实子卷”,"实时子卷"是专门存储文件数据的卷,可以允许将日志与数据分开在不同的磁盘上。

子选项DOS/FAT/NT Filesystems可以添加对Windows相关文件系统的支持。

image-20210917192425001

这里将default codepage for FAT修改为936,将Default iocharset修改为utf8,以支持简体中文。

此外,添加NTFS write support以支持NTFS文件系统的写入功能。

更多关于codepage的相关内容请阅读内核中VFAT文件系统codepage和iocharset设置

子选项Network File Systems中包含网络文件系统的相关设置:

image-20210917193102228

这里添加上对SMB2网络文件系统的支持。

子选项Native language support可以设置语言支持:

image-20210917193415351

简体中文以模块的方式支持。

Kernel hacking

这里是Linux核心开发者会用到的相关功能,如果你不是内核开发人员,应该是用不到的。

Security options

这里是安全相关的选项,包括SELinux的相关设置:

image-20210917193755585

Virtualization

这里包含虚拟化相关的设置。

image-20210917194110777

这里添加一个虚拟化相关的功能KVM legacy PCI device assignment support

到这里所有设置就都选择好了,选择下方的save进行保存:

image-20210917194316878

确认保存到.config,点ok

保存好后一路选择exit退出程序即可。

内核的编译和安装

编译内核和模块

可以通过make help命令查看内核编译的相关命令:

[root@xyz linux-3.10.99]# make help
Cleaning targets:
  clean           - Remove most generated files but keep the config and
                    enough build support to build external modules
  mrproper        - Remove all generated files + config + various backup files
  distclean       - mrproper + remove editor backup and patch files

Configuration targets:
  config          - Update current config utilising a line-oriented program
  nconfig         - Update current config utilising a ncurses menu based program
  menuconfig      - Update current config utilising a menu based program
  xconfig         - Update current config utilising a QT based front-end
  gconfig         - Update current config utilising a GTK based front-end
  oldconfig       - Update current config utilising a provided .config as base
  ...省略

主要的命令有:

  • make vmlinux:将内核编译成未压缩的内核文件。
  • make modules:仅编译内核模块。
  • make bzImage:将内核编译成压缩后的内核文件。
  • make all:执行上边所有的三个操作。

通常编译内核时的步骤是:

  1. make clean:清理上次编译的残留文件。
  2. make bzImage:编译内核。
  3. make modules:编译模块。

或者可以使用组合命令:make clean bzImage modules

此外,为了更高效地编译内核,可以使用-j n命令使用多线程编译内核,其中n可以设置为CPU最大支持的线程数,比如双核四线程的CPU编译内核时可以使用make -j 4 bzImage

现在开始实际编译内核:

[root@xyz linux-3.10.99]# make clean
[root@xyz linux-3.10.99]# make bzImage
...省略
  OBJCOPY arch/x86/boot/vmlinux.bin
  HOSTCC  arch/x86/boot/tools/build
  BUILD   arch/x86/boot/bzImage
Setup is 16720 bytes (padded to 16896 bytes).
System is 4469 kB
CRC d8aafb6f
Kernel: arch/x86/boot/bzImage is ready  (#1)

出现xxx is ready字样就说明编译好了。

下面编译模块:

[root@xyz linux-3.10.99]# make modules
  • 编译前请确保有足够的空闲空间,我因为空间不够编译失败了。
  • 模块编译非常耗时,我几年前的小破笔记本上的虚拟机用单线程跑了1小时左右。

安装模块

内核模块都安装在/lib/modules/$(uname -r)目录下。也就是说以内核版本进行区分,一般来说不会有什么问题,但如果我们要安装的内核模块对应的版本已经存在了,就会产生冲突。此时解决的方式有:

  • 将旧的内核模块所在目录名修改后进行安装。
  • 在内核设置中将General setup中的Local version中添加一个额外的版本标识。

如果不存在版本冲突的问题就可以直接安装:

[root@xyz linux-3.10.99]# make modules_install
...省略
  INSTALL /lib/firmware/edgeport/down2.fw
  INSTALL /lib/firmware/edgeport/down3.bin
  INSTALL /lib/firmware/whiteheat_loader.fw
  INSTALL /lib/firmware/whiteheat.fw
  INSTALL /lib/firmware/keyspan_pda/keyspan_pda.fw
  INSTALL /lib/firmware/keyspan_pda/xircom_pgs.fw
  DEPMOD  3.10.99icexmoon
[root@xyz linux-3.10.99]# ll /lib/modules
总用量 8
drwxr-xr-x. 7 root root 4096 7月  24 14:46 3.10.0-1160.el7.x86_64
drwxr-xr-x. 3 root root 4096 9月  17 21:59 3.10.99icexmoon

安装内核与实现多重引导

安装内核

安装内核实际上就是将编译好的内核文件部署到/boot目录:

[root@xyz linux-3.10.99]# cp ./arch/x86/boot/bzImage /boot/vmlinuz-3.10.99icexmoon
[root@xyz linux-3.10.99]# cp .config /boot/config-3.10.99icexmoon
[root@xyz linux-3.10.99]# chmod a+x /boot/vmlinuz-3.10.99icexmoon
[root@xyz linux-3.10.99]# cp ./System.map /boot/System.map-3.10.99icexmoon
[root@xyz linux-3.10.99]# gzip -c Module.symvers > /boot/symvers-3.10.99icexmoon.gz
[root@xyz linux-3.10.99]# restorecon -Rv /boot
restorecon reset /boot/System.map-3.10.99icexmoon context unconfined_u:object_r:boot_t:s0->unconfined_u:object_r:system_map_t:s0

这里除了内核文件,还拷贝了其它关键文件到/boot目录。

创建对应的虚拟文件系统

我们之前说过,内核在加载到内存中后,要依靠虚拟文件系统才能读取到模块,所以还要创建新内核的虚拟文件系统:

[root@xyz linux-3.10.99]# dracut -v /boot/initramfs-3.10.99icexmoon.img 3.10.99icexmoon
Executing: /sbin/dracut -v /boot/initramfs-3.10.99icexmoon.img 3.10.99icexmoon
dracut module 'busybox' will not be installed, because command 'busybox' could not be found!
dracut module 'dmsquash-live-ntfs' will not be installed, because command 'ntfs-3g' could not be found!
dracut module 'cifs' will not be installed, because command 'mount.cifs' could not be found!
...省略
*** Creating image file ***
*** Creating image file done ***
*** Creating initramfs image file '/boot/initramfs-3.10.99icexmoon.img' done ***

多重引导

要让新内核能使用还需要让其出现在boot loader的引导菜单上才行,所以这里需要重建grub2的配置文件,以让grub2自动识别到新内核:

[root@xyz linux-3.10.99]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.99icexmoon
Found initrd image: /boot/initramfs-3.10.99icexmoon.img
Found linux image: /boot/vmlinuz-3.10.0-1160.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-f5a85e92d51e4d40975fd956fd775f9c
Found initrd image: /boot/initramfs-0-rescue-f5a85e92d51e4d40975fd956fd775f9c.img
done

可以看到识别到了我们的新内核。

测试

现在新内核已经就绪,重启来看看:

image-20210917221541876

第一个选项就是新内核,选择新内核进入系统。

[icexmoon@xyz ~]$ uname -r
4.1.16

内核更新成功。

  • 花了两天时间总算成功安装了一个官方内核,不过兼容性依然有点问题,GNOME窗口管理器就很卡。安装过程中我同样参考了CentOS7编译内核 详细步骤
  • 遇到的其它坑包括:
    • 安装最新的内核5.9.9时,各种编译工具均版本过老,无法编译,如果强行要编译可能还需要找其它的软件源更新编译工具,我这里没有继续折腾。
    • 安装内核3.10.99后,无法正常进入系统,显示不能加载/dev/dm-0centos-root),猜测应该是因为/root所在分区使用的是LVM,且因为空间不够我进行过扩若,导致出现了xfs的一个BUG,该BUG影响3.10~3.12的所有内核版本,详情请见xfs.org
    • 安装内核3.13.13.19.8后,无法正常进入系统,VMware虚拟机直接报错:操作系统拒绝CPU。网上有说法是内存太小,但我遇到的问题并不完全一致,是完全没有内核的加载过程输出,修改虚拟机内存大小后问题也依然存在。

以上就是Linux内核编译的全部内容了,谢谢阅读。

到这里,《鸟哥的Linux私房菜》这本书就全部学习完毕了,可能还有一两篇文章作为番外以及该书的书评。

这篇关于Linux 之旅 24:内核编译的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!