Linux 内核编译初步

说起内核编译,很多人都会觉得应该会很难,毕竟涉及到一个系统的核心文件。其实对于内核,在《Grub Legacy 简介》中已经有过接触,就是那个 vmlinuz-2.6.32-431.el6.x86_64 文件。对于交叉编译,进行其他主机系统的内核编译,确实比较麻烦;但是如果只是为了升级当前系统的内核,而不改变其他配置的话,还是相对简单的。下面说的也主要是升级内核所进行的内核编译步骤。

准备工作

要进行内核编译,得提前做好以下准备工作:

  1. 准备好开发环境;
  2. 获取目标主机上硬件设备的相关信息;
  3. 获取到目标主机系统功能的相关信息,例如要启用的文件系统;
  4. 获取内核源代码包;

准备开发环境

若要编译内核,需要在编辑机上安装开发套件。

1
2
3
sudo yum groupinstall "Development Tools";
sudo yum groupinstall "Server Platform Development";
sudo yum install ncurses ncurses-devel;

获取主机硬件信息

获取主机硬件信息是至关重要的一步,关系到所编译成的内核是否与硬件兼容,是否能发挥硬件的最大效用。如果是本机升级内核并且之前保存有内核编译配置的话(一般系统安装时都会存有一份),可以直接覆盖使用。

CPU

cat /proc/cpuinfo;

lscpu;

Memory

内存不需要具体型号参数,只需要知道空间大小即可。

free;

PCI

lspci;

lsusb; (需安装 usbutils

lsblk;

查看全部硬件信息

hal-device; (需安装 hal

获取系统功能信息

这个跟定制化系统相关,比如是否需要 IPV6 ,甚至于是否需要网卡驱动之类的。

获取内核源代码包

访问 https://www.kernel.org/pub/linux/kernel/ 获取想编译的内核源码包。

开始编译

本机内核为 2.6.32 ,现在要升级为 2.6.39

1
2
3
4
5
[hzz@magedu ~]$ uname -r
2.6.32-431.el6.x86_64
[hzz@magedu ~]$ ls
linux-2.6.39.tar.gz
[hzz@magedu ~]$

解压源码包

下载源码包后,将源码包解压到 /usr/src/ 目录。

1
2
3
4
5
[hzz@magedu ~]$ sudo tar zxf linux-2.6.39.tar.gz -C /usr/src/
[hzz@magedu ~]$ cd /usr/src/
[hzz@magedu src]$ sudo ln -s linux-2.6.39 linux
[hzz@magedu src]$ cd linux
[hzz@magedu linux]$

配置内核选项

输入 make help 可以得到很多配置选项,抽取一些常用的进行说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Configuration targets:
config - Update current config utilising a line-oriented program
- 基于命令行以遍历的方式去配置内核中可配置的每个选项;
nconfig - Update current config utilising a ncurses menu based program
- 基于 cureses 的文本配置窗口; * 表示编译进内核, M 表示编译进模块;
menuconfig - Update current config utilising a menu based program
- 文本配置窗口; * 表示编译进内核, M 表示编译进模块;
xconfig - Update current config utilising a QT based front-end
- 基于 QT 开发环境的窗口界面;
gconfig - Update current config utilising a GTK based front-end
- 基于 GTK 开发环境的窗口界面;
oldconfig - Update current config utilising a provided .config as base
- 基于旧的 .config 文件来更新当前配置;
defconfig - New config with default from ARCH supplied defconfig
- 基于内核为目标平台提供的默认配置为模板进行配置;
allnoconfig - New config where all options are answered with no
- 创建一个所有选项都是 no 的配置文件(适用于想完全自定义内核的操作);
allyesconfig - New config where all options are accepted with yes
- 创建一个所有选项都是 yes 的配置文件(编译出来的内核会非常大);

* Update 开头的都是基于旧配置或当前配置进行修改, New 开头的则是重新创建新配置文件。
* 配置完成后会在当前目录生成一个 .config 文件,可直接进行编辑,或用系统安装时所生成的 config 配置重命名后进行替换。
* CentOS 安装时保存的内核编译配置文件路径为:/boot/config-2.6.32-431.el6.x86_64 。

比如,执行 sudo make menuconfig 后,便会弹出一个图形化的菜单编辑界面,可以自定义内核参数。

config 菜单

选择支持的文件系统

由于此次主要是为了升级内核,其他不作什么大的改变,故基于系统安装时保存的配置文件进行修改。为了更好地识别新旧内核,添加 Local version 的参数为 -magedu-hzz

1
2
[hzz@magedu linux]$ sudo cp /boot/config-2.6.32-431.el6.x86_64 /usr/src/linux/.config
[hzz@magedu linux]$

menuconfig

menuconfig

menuconfig

编译内核

编译内核其实很简单,就一条命令的事,其实最麻烦的还是配置内核选项阶段,若想了解每一个选项的作用及影响,是需要不少时间的。

由于编译花费时间较长,推荐使用 screen 命令进行编译,以避免终端超时退出导致编译失败的情况。

先简单说说 screen 命令的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# screen :打开一个与终端无关的窗口,终端断开后还依旧运行。

# 安装 screen
sudo yum install screen

# 打开 screen
screen

# 拆除 screen
Ctrl+a,d

# 列出 screen
screen -ls

# 连接至 screen
screen -r SCREEN_ID

# 关闭 screen
screen 内执行 exit

kill SCREEN_ID

下面开始编译内核:

1
[hzz@magedu linux]$ sudo make && sudo make modules_install && sudo make install

编译完成后,会在 /boot 目录下看到新的内核镜像,以及在 grub.conf 中看到新添加的内核启动选项:

1
2
3
4
5
6
7
8
9
10
11
[hzz@magedu ~]$ ls -ltr /boot/|grep magedu-hzz
lrwxrwxrwx. 1 root root 31 10月 31 19:59 vmlinuz -> /boot/vmlinuz-2.6.39-magedu-hzz
-rw-r--r--. 1 root root 2364066 10月 31 19:59 System.map-2.6.39-magedu-hzz
lrwxrwxrwx. 1 root root 34 10月 31 19:59 System.map -> /boot/System.map-2.6.39-magedu-hzz
-rw-r--r--. 1 root root 3931776 10月 31 19:59 vmlinuz-2.6.39-magedu-hzz
-rw-------. 1 root root 5977054 10月 31 19:59 initramfs-2.6.39-magedu-hzz.img
[hzz@magedu ~]$ more /boot/grub/grub.conf |grep magedu-hzz
title CentOS (2.6.39-magedu-hzz)
kernel /vmlinuz-2.6.39-magedu-hzz ro root=/dev/mapper/vg_magedu-lv_root rd_NO_LUKS rd_LVM_LV=vg_magedu/lv_swap rd_NO_MD rd_LVM_LV=vg_magedu/lv_root crashkernel=auto LANG=zh_CN.UTF-8 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.39-magedu-hzz.img
[hzz@magedu ~]$

启用新内核

重启系统,选择新内核启动:

新内核

启动完成后,使用 uname -r 命令,可以看到当前使用的已经是最新的内核了:

1
2
3
[hzz@magedu ~]$ uname -r
2.6.39-magedu-hzz
[hzz@magedu ~]$

其他

多线程编译

如果编译机的性能够强悍,可以在编译时使用多线程同时编译,以节约时间。

1
2
# 四个线程同时编译
[hzz@magedu linux]$ sudo make -j 4

编译内核中的一部分代码

只编译某子目录中的相关代码:

1
[hzz@magedu linux]$ sudo make path/to/dir/

只编译一个特定模块

1
[hzz@magedu linux]$ sudo make path/to/dir/file.ko

交叉编译

如果需要为其他主机编译内核,可以到 arch 目录下查看支持的平台,然后使用 ARCH 变量指定目标主机的平台进行设置:

1
2
3
4
[hzz@magedu linux]$ ls arch/
alpha avr32 cris h8300 Kconfig m68k mips parisc s390 sh tile unicore32 x86_64
arm blackfin frv ia64 m32r microblaze mn10300 powerpc score sparc um x86 xtensa
[hzz@magedu linux]$ sudo make ARCH=arm menuconfig

执行清理

如果需要在同一个源码中对不同的平台的内核进行编译,则在编译前需清理上一次编译产生的文件:

1
2
3
# make clean :清理编译生成的绝大多数文件,但会保留 config ,及编译外部模块所需要的文件;
# make mrproper :清理编译生成的所有文件,包括配置生成的 config 文件及某些备份文件;
# make distclean :相当于 mrproper ,额外清理各种 patches 以及编辑器备份文件;