1. 内核编译的基本流程
- <获取源代码>, 如有需要则进行修改;
- <配置>;
- <编译>;
- [根据发布版生成相应的源码包];
- <安装内核映像和模块>。
<>为必需的步骤,[ ]为可选的步骤。
若不使用发布版的源码包管理系统, 则不需要进行步骤
4。 想要使用源码包管理系统来安装时, 可以使用各发布版的源码包创建系统。 在这种情况下步骤 3 和步骤 4 的操作是合并进行的。
2. 准备工作
2.1 工具的安装
- Fedora发行版
源码包名 | 备注 |
---|---|
ncurses-devel | 基于控制台( 文字界面) 设置时需要 |
qt-devel | 基于窗口( 图形界面) 设置时需要 |
qt3-devel | 基于窗口( 图形界面) 设置时需要 |
gcc-c++ | 基于窗口( 图形界面) 设置时需要 |
rpm-build | 生成 rpm 包时需要 |
- Ubuntu发行版
源码包名 | 备注 |
---|---|
libncurses5-dev | 基于控制台( 文字界面) 设置时需要 |
qt3-dev-tools | 基于窗口( 图形界面) 设置时需要 |
g++ | 基于窗口( 图形界面) 设置时需要 |
kernel-package | 生成 deb 包时需要 |
fakeroot | 生成 deb 包时需要 |
dpkg-dev | 生成 deb 包时需要 |
2.2 获取源代码
不再赘述。参考:一文搞懂Linux系统内核升级及下载当前内核源代码
在此,假设源代码(linux2.6)已经下载到当前家目录~/linux-2.6/。
3. 配置
源代码树中自带有帮助进行设置的工具。 这个工具包称为 kconfig。设置工具有基于控制台( 文字界面) 和基于窗口( 图形界面) 的两种类型, 这里主要以基于控制台的工具为例展开介绍, 基于窗口的工具仅在后面简单介绍。
1. 选择目标机器的架构,并进行默认配置
在源码树中分别为每个架构准备了默认的 .config
文件,位于arch/<arch>/configs/*_defconfig
,执行下列命令:
$ make defconfig
2. 根据需要修改内核配置
要启动基于控制台的设置工具, 需在源码树的根下执行下列命令:
$ make menuconfig
【 y】 键:左侧的选择显示就会变成 <*>。 这就表示该项目已编译并静态添加到内核中。
【 m】 键, 显示则变成 。 这时, 该项目将作为模块编译。 当使用该功能时, 模块会根据需要动态添加到内核中。
【 n】 键, 则会变成 <>, 该功能不编译。
大致完成自己想要的设置后, 可以在菜单最上层的画面上选择操作菜单的 , 或者连按两次【 Esc】 键完成设置, 在出现的“是否保存新设置? ”对话框中选择 Yes 按钮,将设置保存到 .config 文件中。到这里, 内核的编译设置就完成了。
- 小彩蛋
经常有人因为手头有在旧版本中生成的 .config 文件, 而想要在此基础上进行一些修改,以编译新的内核。 在这种情况下, 可以将原来的 .config 文件复制到源码树的根下, 然后执行命令$ make oldconfg
, 就会出现一个个的对话框, 询问新增加的设定项目要如何设置。 如果版本之间的差别较大, 就需要回答较多的项目设置问题, 所以可以先针对所有的询问都按回车键, 以便使用默认设置, 然后再用 make menuconfig 等进行设置。
4. 编译
4.1 直线编译
当所编译的内核要运行的目标机为本地时,只需在源码树的根目录下执行:
$ make
编译时间与机器性能有较大的关系, 从几分钟到几小时不等。那有哪些节约编译时间的方法呢?
- 在内核的配置上
将目标环境中不需要的驱动程序设置为无效, 仅将必要的功能或模块作为编译对象。 - 在编译选项上
-j 选项用来指定 make 的并发性, 当机器为多处理器时可以按照处理器的数量来指定数值, 这样就有可能实现快速编译。 - 在机器性能上
使用高性能的宿主机进行内核编译。
4.2 交叉编译
- 交叉编译是指针对与正在执行编译的平台不同的其他平台生成二进制数据。 例如, 在x86_64 环境下生成针对 ARM 的二进制数据的情形。 这种编译器又称为“交叉编译器”。
- 只要拥有交叉编译器, 对 Linux 内核进行交叉编译就变得非常简单。 这时只需要为 make赋予两个变量:
变 量 | 说 明 |
---|---|
ARCH | 目标机架构 |
CROSS_COMPILE | 指定交叉编译器的前缀 |
- 例如:使用armv5tel-linux-gcc 来交叉编译 ARM 内核时,使用如下命令:
$ make ARCH=arm CROSS_COMPILE=armv5tel-linux- uImage
$ make ARCH=arm CROSS_COMPILE=armv5tel-linux- modules
- 最后,将创建的内核和模块转移到对象机器上安装就可以了。
- 创建的内核二进制映像uImage位于源码树的
arch/arm/boot/
下,但创建的模块却位于源码树的各个目录中,想要手动查找这些模块是不现实的。所以我们在编译模块时可以通过变量INSTALL_MOD_PATH
来指定指定模块的存放路径:
$ make ARCH=arm CROSS_COMPILE=armv5tel-linux- INSTALL_MOD_PATH=~/armroot-2.6.38 modules_install
- 这样就会在主目录下生成一个标题为
~/armroot-2.6.38/lib/modules
的目录, 模块就安装在这个目录下。模块的目录下有标题为 build 和 source 的符号链接, 这些都是指向编译过内核的源码
树。 如果在对象机器上完全不进行编译, 就不需要进行修改, 如有必要可以在对象机器上适当修改。
4.3 自定义模块编译
有时,除了内嵌模块外,我们更多的是需要编译可加载的模块,它的源代码与内核源码树并不在同一个目录树下,而是分开提供的。在这种情况下, 需要驱动程序源代码正确编写 Makefile, 并按照下列方法进行编译、 安装:
$ make –C /lib/modules/$(uname -r)/build M=$PWD
$ make –C /lib/modules/$(uname -r)/build M=$PWD modules_install
-C 选项:指向内核源目录的符号链接。
-M选项:告知 Linux 内核的创建操作正在源码树外执行创建操作。
5. 安装
5.1 本地安装
安装分为三个阶段进行。
第一阶段是模块的安装,在编译完成的源码树的根目录下执行
命令:
$ sudo make modules_install
这时, 编译后的模块就安装到 /lib/modules 下。
第二阶段是安装内核二进制映像文件, 生成并安装 boot 初始化文件系统映像文件。 同样在源码树的根目录下执行下列命令:
$ sudo make install
这时, 内核映像文件就安装到 /boot 下。
- 如果使用的是 Fedora 系列的发布版, 就会同时生成 boot 初始化文件系统映像, 并同样安装到 /boot 下。
- 如果是 Ubuntu 等 Debian 系列的发布版则需要执行
sudo update-initramfs –c –k < 内核版本 >
命令, 另行生成和安装 boot 初始化文件系统映像。 在 < 内核版本 > 的部分请输入表示当前生成的内核版本的文字。
下表为通过内核安装生成的文件以及目录的一览表:
文件名或目录名 | 内 容 |
---|---|
/lib/modules/< 内核版本 > | 安装模块的目录 |
/boot/vmlinuz-< 内核版本 > | 内核映像文件 |
/boot/initramfs-< 内核版本 > 或/boot/initrd.img-< 内核版本 > | boot 初始化文件系统映像 |
/boot/Systemmap-< 内核版本 > | 地址信息文件 |
第三阶段修改启动文件。在一些系统设置下可能需要手动进行 GRUB 设置才能从当前安装的内核启动。 在这种情况下, 请适当地编辑/boot/grub/menu.lst
或者执行 update-grub
命令。
这时请重启机器, 确认新的内核是否能够正常运行。
注意:内核映像的文件名和模块目录名是根据内核的版本来命名的。 因此, 当对已安装版本的内核进行再次编译并安装时, 原来安装的内核以及模块会被覆盖。为了防止这种情况的发生, 可以在内核配置选项CONFIG_LOCALVERSION 中添加字符,它会作为内核版本的一部分, 因此可以防止被覆盖。
- 小彩蛋:
在进行内核的设置或编译时, 有一些可用的 make 目标:
make对象 | 说 明 |
---|---|
clean | 将源码树恢复到编译前的状态。 obj 文件等被删除, .config或编译过程中自动生成的部分文件不会被删除 |
mrproper | 将源码树完全恢复到发布时的状态。 发布时源码树中不存在的文件全部被删除, 包括 .config 文件 |
help | 显示可以使用的 make 对象 |
tags | 生成标签文件。 有了标签文件, 就能使用 Emacs 等编辑器的tag jump 功能跳到函数定义处, 可以高效进行源码浏览 |
cscope | 生成用于 cscope 的索引文件。 cscope 是基于控制台( 文字界面) 的源码浏览器 |
allyesconfig | 生 成 将 所 有 设 置 项 目 设 置 为 有 效 并 静 态 添 加 到 内 核中的 .config 文件 |
allnoconfig | 生成将允许范围内的设置项目设置为无效的 .config 文件 |
allmodconfig | 生成将所有能设置为模块的项目设置为有效并设置为模块的 .config 文件 |
<dir>/<file>.o | 仅进行生成指定的目标文件所必需的编译。 当仅指定 <dir>时, 由 .config 文件生成该目录内所有目标文件 |
<dir>/<file>.ko | 仅生成指定的模块 |
- 为控制 make 的输出而设置的 make 变量。 这些变量需在对象前指定, 如:
$ make V=1 clean
make选项 | 说 明 |
---|---|
V=0|1|2 | 设置编译时控制台显示的详细程度。 默认为仅显示概要, 设置为 0。 当设置为 1 时, 显示更加详细的信息。 当设置为 2 时,除了概要以外, 还会显示要进行编译的原因( 原因大多数都是“由于没有对象”) |
O=<dir> | 将编译最终生成的文件全部输出到 <dir>。 在源码树禁止写入等情况下非常实用。 |
5.2 利用包管理工具安装
要将内核镜像纳入包管理范围内, 就需要生成相应的源码包。
- Fedora
Fedora的源码包管理系统是 rpm。 Linux 内核在创建时就具备生成 RPM 源码包的功能。 编译时需要将 rpm-pkg 作为对象执行 make 命令:
$ make rpm-pkg
执行命令后会创建源码包( SRPM) 和二进制码包( RPM), 二进制码包存放在~/rpmbuild/rpms
下, 源码包存放在 ~/rpmbuild/SRPMS
下。
如果拥有将 SRPM 解压缩后的发布版内核的源码, 则使用 rpmbuild 创建源码包。 如果内核的 SRPM 是解压缩到 ~/rpmbuild 下的, 则执行下列命令创建源码包:
$ rpmbuild –ba ~/rpmbuild/SPECS/kernel.spec
所创建的源码包存放的目录与上面相同。 这些源码包和普通源码包一样, 可以使用 rpm命令来安装、 卸载。
- Ubuntu
Ubuntu 的源码包管理系统是 dpkg。 源码包为 deb 格式。与 RPM 同样, 也能生成 deb 源码包。 这一 make 操作的对象为 debpkg。 通过执行下列 make 命令, 就能够创建 deb 源码包:
$ make deb-pkg
所创建的源码包存放在源码树的根目录下。 会生成数个源码包, 其中包含内核映像和模块的是 linux-image-< 内核版本 >.deb
文件。 这些源码包的操作和普通的 deb 源码包文件
一样, 可以用 dpkg 来进行安装。
此外, Ubuntu 还在 kernel-package 包里收录了用来协助内核包创建的工具—makekpkg 命令。 这个工具可以通过命令选项对创建操作进行设置, 根据需要呢你也可以使用这个工具。
6. 卸载
- 利用发布版源码包管理系统安装的内核,可以用 rpm 或 dpkg 这样的命令来卸载。
- 本地直接安装的,只需要参照5.1节所列内核的文件配置,删除这些文件就可以了。
注意事项: 卸载内核时请慎重考虑。 另外, 请一定要做好更改 GRUB 设置等工作。
更多精彩文章,请关注leon的博客小站