# Linux Kernel Build

OS类型分类

这是操作系统系统的分类图,也是目前市场上存在的集中不同的操作系统设计思想,分别是:

  • 宏内核:操作系统提供较为完备的运行组件
    • 目的:通用性,完备性
  • 微内核:操作系统仅提供基础系统服务的组件
    • 目的:精简性,移植性
  • 混合内核:鉴于前两种之间
    • 目的:获取前两者的优点的平衡点

关于不同设计思想和好坏,这里不做具体比较,后面我们会专门分析这个内容,这里我们主要是有这个概念,并了解到我们的 Linux 使用的是宏内核的设计方法,下图为 Linux 内核的基本组件内容,对应后面的各个部分,我们能在宏观上对整个 Linux 内核的构成有了解。

image-20200918162606882


# Get Source Code

Linux Code 阅读器能够在线查阅源码,The Linux Kernel documention 能够查阅到 Linux 版本的改动和一些开发的示例,源码下载可以在官网,如果网络太慢的话,可以使用中国的镜像站,例如清华镜像站等,下载的格式一般是 tar.gz ,然后执行以下的命令进行解压

#bash
$ tar -zxvf ./xxx.tar.gz #解压源码

然后我们可以使用 tree 这个工具对整个内核的文件目录架构有个直观的理解,执行以下的命令

#bash
$ tree -L 1 #查看树状的目录内容 深度为 1

如果没有该工具,可以使用 sudo apt install tree 进行下载

然后我们能看到这样的内容结构:

image-20210203164129454

文件夹部分:

  • doucumentation :说明文档,对每个目录的具体作用进行说明。

  • arch : 存放不同架构下的硬件的初始化代码和相关的配置文件

    • arch/xxx/config :该架构下的一般配置文件
  • block :部分块设备驱动程序

  • certs :和证书相关

  • crypto :加密,压缩, CRC 校验算法

  • drivers : 驱动源码,这里包含所有提交到 Linux 社区的驱动,可以在配置文件勾选是否编译进去

  • fs :文件系统源码,这里包含了所有文件系统支持的源码,也可以在配置文件中进行勾选

  • include : 通用头文件包括对通用硬件,软件等的支持

  • init :这里包含的 init 进程的动作,也就是跳转到内核后开始执行的

  • ipc :这里包含了进程间通信的机制和逻辑实现

  • kernel : 这里包含了内核的核心通用代码的实现

    • kernel/config : 一般的配置文件
    • /boot/config-x.xx.x-xx-xxxxxx 当前正在运行内核的配置文件
  • lib :程序的共享库的源文件,库文件代码 (与平台相关的)

  • mm :内存管理的源码

  • net :网络相关的源码

  • usr :统一系统资源的源码

  • security :Selinux 的模块

  • sound :音频设备的驱动程序

  • Scripts :编译过程中会执行的一些脚本程序

文件部分:

文件名作用
COPYING许可和授权信息。
CREDITS贡献者列表。
Kbuild内核设定脚本,可以对内核中的变量进行设定。
Kconfig配置哪些文件编译,那些文件不用编译。
Makefile该文件将编译参数、编译所需的文件和必要的信息传给编译器。

# Prepare The Environment

在环境准备这里我们介绍了两种不同的内核准备环境,然后我们根据自己的需求进行配置即可

  • 通用 PC 的内核环境准备
  • 实时 PC 的内核环境准备

需要根据不同的架构下载相应的工具链,具体可以参考以下命令:

# ARM

  • 对于 ARM 32 位工具链
$ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
  • 对于 ARM 64 位工具链
$ sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
  • 安装程序包依赖项
$ sudo apt-get install build-essential autoconf libtool cmake pkg-config git python-dev swig3.0 libpcre3-dev nodejs-dev

# RISC-V

Toolchain:https://github.com/riscv/riscv-gnu-toolchain

  • 安装必要的编译工具依赖
$ sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
  • 编译工具的安装
$ ./configure --prefix=/opt/riscv
$ make

# Normal Kernel

依赖包的安装,因为在编译过程中会使用一些软件和依赖库,以下为一般依赖安装的要求

#bash
$ sudo apt update #更新源
$ sudo apt-get install build-essential # 常用构建工具集 包含(g++ gcc make dpkg lic6)
$ sudo apt install ncurses-base ncurses-bin #依赖包:是一个程序库,它提供了 API: 文字终端
$ sudo apt install libncurses5-dev  #lib 版本的依赖包
$ sudo apt install flex bison  #flex 弹性布局  bison 通用解析器生成器
$ sudo apt install libssl-dev  # 安全套接字协议
$ sudo apt install libelf-dev elfutils  #ELF 目标文件访问库  elfutils 用于读取,创建和修改 ELF 二进制文件

# Real-Time Kernel

Linux 源码没有实现硬实时,为了实现抢占式的内核环境,我们需要使用上游 Linux 社区提供的实时补丁,来使得内核编译提供硬实时的环境,因此我们首先需要从网站获取补丁,我们需要找到对应版本的补丁。下载文件的格式为 tar.gz ,然后放在 Linux Kernel 源码文件夹同级的目录。需要注意的是:如果你使用版本过新,有可能该版本社区仍未提供补丁。亦或是你的版本并没有在社区提供支持的计划内。因此有实时需求的使用者,建议先到网站查阅提供的内核版本补丁的列表,然后再根据项目需求到选择内核版本。

硬实时:不仅要求任务响应要实时,而且要求在规定的时间内完成事件的处理

下载后,执行以下命令

#bash
$ tar -xzvf linux-5.6.19.tar.gz #解压内核
$ gunzip patch-5.6.19-rt12.patch.gz #解压补丁
$ cd linux-5.6.19/
$ patch -p1 < ../patch-5.6.19-rt12.patch #打补丁

接下来就是依赖包的安装

#bash
$ sudo apt update #更新源
$ sudo apt-get install build-essential # 常用构建工具集 包含(g++ gcc make dpkg lic6)
$ sudo apt install ncurses-base ncurses-bin #依赖包:是一个程序库,它提供了 API: 文字终端
$ sudo apt install libncurses5-dev  #lib 版本的依赖包
$ sudo apt install flex bison  #flex 弹性布局  bison 通用解析器生成器
$ sudo apt install libssl-dev  # 安全套接字协议
$ sudo apt install libelf-dev elfutils  #ELF 目标文件访问库  elfutils 用于读取,创建和修改 ELF 二进制文件

# Configure Kernel Build

#bash
$ cd linux-x.x.xx
# 拿到你想要配置的 config 文件
$ cp /arch/arm64/config/defconfig .config #将配置文件复制到一级目录
# 以下六选一!!!只需要执行一次
$ make config #老的 make 方式,使用的时每一次弹一句问 y/n
$ make oldconfig # 与上面这种类似,默认一样的配置不会弹出,新配置才会弹出提问
$ make menuconfig # 文字终端的图形化,推荐使用
$ make xconfig #图形化的配置 (需要安装图形化系统)
$ make kconfig #(KDE 桌面环境下,并且安装了 qt 开发环境)
$ make gconfig #(Gnome 桌面环境,并且安装 gtk 开发环境)

这里我们演示了 make menuconfig

Normal

一般情况下,我们需要改动的主要是通用设置(也就是 General Setup ),除非需要进行内核定制或者裁剪的时候,我们才会去修改其他具体的配置项。

界面的介绍:

  • [] :编译可选项,有两种状态, [*][] ,表示编译进内核和不编译进内核。

  • <> :编译可选项,有三种状态, <*><M><> ,表示编译进内核,编译成模块化作为加载模块,不编译进内核。

  • {} :编译形式(一定要编译的),有两种 {*}{M} ,表示编译进内核和编译成模块化作为加载模块。

  • -- :依赖编译内容,因为开启一些编译选项而需要的依赖内容

控制介绍:

方向键:控制上下左右移动

Space :选择选项的内容

操作功能
方向键移动光标
Space Bar (空格键)改变选项
Esc Esc退回上一级
Enter进入该内容
h查看内容的帮助界面

# Optional

image-20210203182027993

# Unnecessary

这部分往往是我们不需要开启的编译内容,能够帮我们加快编译速度和精简内核

选项意义
Compile also drivers which will not load在选项中没有作为可加载模块的驱动也进行编译
Automatically append version information to the version string在编译完成后的名称加上版本信息
Build ID Salt用于验证编译的唯一性和可行度,一般用于分发版本的编译
Default init path可以修改 init 启动程序的文件目录
((none)) Default hostname主机名修改,看个人喜好
General notification queue内核事件能够传递到用户态
auditing infrastructure审核架构支持,使用 SELinux 才需要开启
Expose irq internals in debugfs中断 debug 才需要开启
Make expert-level adjustments to RCU configuration一般开发者用不到 RCU 的专家配置
Checkpoint/restore support进程 debug 的一些特性支持
Kernel->user space relay support如果有大量从内核态到用户态才需要开启
Include all symbols in kallsyms并不需要开启,会把素有的 symbols 包含进来
PC/104 support104 bus 支持
Kernel Performance Events And Counters默认不开启
Enable SLUB debugging support <br /> Enable memcg SLUB sysfs support by default <br />内存 debug 相关的,一般不开启
Disable heap randomization <br /> Harden slab freelist metadata <br /> Page allocator randomization <br />不开启,这是一个安全选项,没这种需求可以不开启
Profiling support不开启,除非需要分析支持

# Necessary

这部分往往是我们需要开启的编译内容,因为这是系统的基本运行依赖组件,取消后会导致系统异常

选项意义
Support for paging of anonymous memory (swap)交换分区支持,扩大虚拟内存的空间,提高系统 io 访问的性能
System V IPC进程间通讯的方式
POSIX Message Queues消息队列,也是进程见通讯的方式
Enable process_vm_readv/writev syscalls开启两项系统调到用,主要用于进程间直接读写操作
Timer tick handling (Idle dynticks system (tickless idle))设置定时器的滴答,我们选择 <br /> Idle dynticks system (tickless idle) 该模式能够再 CPU 没有任务是,动态调整以达到节能的目的 <br /> 其他两个选项一个是固定滴答,一个是全调节滴答
Old Idle dynticks config老版本的配置
CPU/Task time and stats accounting主要是进程的信息统计,保持系统默认,可用于检测状态
Kernel .config support用于 Kernel 配置文件解析支持
Control Group supportCGroup 支持,需要保持默认
Namespaces support命名空间支持,也要保持默认
Initial RAM filesystem and RAM disk (initramfs/initrd) support目前认识主流的初始化 ramfs 的方式,其中压缩方式 Lz4 是最快,Gzip 最通用
Compiler optimization level默认 O2
Configure standard kernel features保持默认即可,除非你是专家
Enable bpf() system call <br /> Enable userfaultfd() system call <br /> Enable rseq() system call这是系统调用的支持,看不懂你就可以关掉。
Choose SLAB allocator建议选择 slab ,具体可以了解内存管理
Allow slab caches to be merged开启,用于回收 cache 的内存碎片

# Consideration

选项意义
uselib syscall如果运行程序有基于 libc5 之前版本编译的,需要开启这一项支持。
High Resolution Timer Support如果计算机支持高分率的定时器,可以开启。否则没有任何意义,只会加大内核镜像的大小
Preemption Model抢占模式选择 <br /> No Forced Preemption 一般服务器使用,保证吞吐量 <br /> Voluntary Kernel Preemption 一般普通 PC 用户 <br /> Preemptible Kernel 用于特定相应的终端,像 TV 等 <br /> Full Preempt Kernel 用于需要硬实时的设备。注意!需要打补丁后才能选择。
Kernel compression mode内核的压缩方式,最快最优压缩是 LV4,最通用是 Gzip
CPU isolation确保运行关键任务的 CPU 不受任何 “噪声” 源(例如未绑定的工作队列)的干扰
Automatic process group scheduling进程自动调度,主要是能够让 CPU 均衡负载,但是可能会损失任务对 CPU 的亲和性
Enable deprecated sysfs features to support old userspace tools未兼容过去工具的,具体请 help 详细阅读
Boot config support开启对启动配置文件解析的支持
SLUB per cpu partial cache开启后能够加速读取

# Build Kernel

编译前准备

#bash
$ make prepare # 编译前准备

然后选择编译工具,如果是交叉编译,需要安装目标系统的编译工具链

#bash
$ make ARCH=xx.xxx  #xx.xx 是编译工具链

这里有两个选项:

make zImage

make bzImage

区别:在 X86 平台上,zimage 只能用于小于 512k 的内核

#Bash 完成命令
$ make bzImage ARCH=xx.xxx

编译好的内核在: arch/xxx/boot/ 目录下


如果要编译并打包成 deb 可执行以下命令

#bash
$ make -j`nproc` && make -j`nproc` bindeb-pk
$ make dep-pkg

编译好的文件包再源码目录的上一级中


编译模块并安装

#bash
#编译和安装模块
$ make modules
$ sudo make modules_install INSTALL_MOD_PATH=/lib/modules #将编译好的内核模块放在 c/lib/modules 下

安装内核

#自动安装
$ sudo make install 
#手动安装
$ sudo cp linux-x.xx.xx/arch/xxx/boot/bzImage /boot/mylinux-x.x.xx
$ sduo cp linux-x.xx.xx/initrd-x.xx.xx /boot/initrd-x.xx.xx
#非本机手动安装
$ sudo dpkg -i linux-*.deb

更新引导

#Bash
$ sudo update-initramfs -c -k x.xx.xx
$ sudo update-grub # 更新引导
$ sudo update-grub2
$ reboot #测试

# Summary

本文介绍了 Linux Kernel 的基本概念以及编译的基本流程和注意事项,已经常见选项控制,主要是让大家对内核编译有一个了解和实操的指南,是一本指南式博客。

更新于

请我喝[茶]~( ̄▽ ̄)~*

Junwide Xiao 微信支付

微信支付

Junwide Xiao 支付宝

支付宝