《Linux内核设计与实现(第三版)》中所用的内核版本为2.6.34,这个版本太旧了,在高版本系统中编译各种不支持,所以选了Ubuntu 14.04进行编译。
编译准备
编译环境:Ubuntu 14.04
GCC版本:4.8.4
编译的内核版本:Linux 2.6.34
内核源码下载:https://mirrors.edge.kernel.org/pub/linux/kernel/
编译过程
解压源码linux-2.6.34.tar.gz,进入源码目录执行以下命令:
# make mrproper
# make clean
# make config
# make > /dev/null
编译成功后,源码目录所用空间从443M增至4.9G。
上述命令包含三个阶段:
1)清理
make mrproper,该命令用于清除Linux内核源代码树中生成的文件,通常在编译内核时使用,以确保旧的编译产物被完全清除,以开始一个全新的编译过程,该命令会删除所有的编译生成文件、内核配置文件(.config文件)和各种备份文件,所以几乎只在第一次执行内核编译前才用这条命令。
make clean,该命令则是用于删除大多数的编译生成文件,但是会保留内核的配置文件.config,还有足够的编译支持来建立扩展模块。所以若只想删除前一次编译过程的残留数据,只需执行make clean命令。
make mrproper删除的范围比make clean大,实际上make mrproper在具体执行时第一步就是调用make clean。
2)配置
make config,该命令会逐一遍历所有配置项,要求用户选择yes、no或module,这是一种基于文本的传统配置方式,它会为内核支持的每一个特性向用户提问,如果用户输入“y”,则把该特性编译进内核,如果输入“m”,则把该特性变成以模块,如果输入为“n”,则表示不编译该特性,用户的配置选择结果会存入.config文件。
make config比较繁琐耗时,可以使用make menuconfig或GTK+图形界面下的make gconfig来进行配置选择。
还有两条与配置相关的命令:
make defconfig,生成默认配置。
make oldconfig,检查已有的.config文件和Kconfig文件的规则是否一致,如果一致就什么都不做,否则提示用户哪些源代码中有的选项在.config文件没有,让用户进行选择。Kconfig文件是源码中提供用来配置内核的文件,是各种配置界面(包括make config这样的文本方式)所需要的源文件,内核配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核,最后生成配置文件.config。当把一个老版本内核源码中已经配置好的.config
文件拷贝到一个新版本源码文件夹中继续使用时,应该执行make oldconfig命令,因为新版本内核往往会增加配置项。
3)生成
make,生成内核映像和内核模块。
补充:
make bzImage,只生成内核映像。
make modules,只生成内核模块。
make -jn,开启n个并发编译作业,在多核环境中可以极大加快编译速度。
编译报错
1)报错提示:
gcc: error: elf_x86_64: No such file or directory
gcc: error: unrecognized command line option ‘-m’
解决方法:
这是由于gcc 4.6及以上不再支持linker-style架构,需要将arch/x86/vdso/Makefile中,以VDSO_LDFLAGS_vdso.lds开头所在行的“-m elf_x86_64”替换成“-m64”(注意不是-m 64),将VDSO_LDFLAGS_vdso32.lds开头所在行的“-m elf_i386”替换成“-m32”。
2)报错提示:
drivers/net/igbvf/igbvf.h:129:15: error: duplicate member ‘page’
解决方法:
这是因为高版本GCC对旧定义方式不支持所致,把相关结构体struct igbvf_buffer中最后一个struct page *page注释掉或删掉。
内核安装
# sudo make modules_install
# sudo make install
make modules_install是安装内核模块,安装目录为/lib/modules,这里会生成一个以内核版本号2.6.34命名的子目录,存放各个以.ko为后缀的模块文件。
make install是安装内核映像,安装目录为/boot,本次安装中这里被放入四个文件:vmlinuz-2.6.34,initrd.img-2.6.34,System.map-2.6.34,config-2.6.34
vmlinuz:内核映像文件。
initrd.img:initrd是initial ramdisk的简写,意为初始RAM磁盘,是在系统引导过程中挂载的一个临时根文件系统,initrd绑定到内核,并作为内核引导过程的一部分加载,用来支持两阶段的引导过程。initrd文件中包含了各种可执行程序和驱动程序,它们可以用来挂载真正的根文件系统,然后再将这个临时根文件系统卸载,继而释放内存。但在很多嵌入式系统中initrd就是最终的根文件系统。
System.map:这是一份用于调试内核的符号对照表,可以将内核符号和它们的起始地址对应起来,将内存地址翻译成容易理解的函数名及变量名。
config:从其内容来看,该文件记录了make config中对内核各个配置项的选择。
可以执行make modules_install install将内核模块和内核映像一并安装。
在执行make install时,如果/boot目录下已经存在相同版本的内核,已存在内核会被重命名为vmlinuz-x.x.xx.old。
有些教程中需要手动运行mkinitramfs命令以在/boot下创建initrd文件,但本次测试中运行make install后自动创建了initrd文件。
更新引导
执行命令:
# sudo update-grub
选择内核
方式一:
在系统启动时,按shift键进入GRUB菜单,选择”Advanced Options for Ubuntu”,在新菜单页中选择指定版本的内核启动,如”Ubuntu, with Linux 2.6.34″。
方式二:
编辑文件/etc/default/grub,添加配置:GRUB_TIMEOUT_STYLE=menu再执行update-grub命令更新GRUB配置,系统重启后会自动进入GRUB菜单,再选择指定版本的内核启动。方式三:直接指定开机启动项,编辑文件/etc/default/grub,将配置GRUB_DEFAULT=0修改如下:GRUB_DEFAULT=”1>4″
其中,1表示在第一个菜单页中选择第2项,也即”Advanced Options for Ubuntu”,4表示在第二个菜单页中选择第5项,也即”Ubuntu, with Linux 2.6.34″再执行updage-grub命令更新GRUB配置,系统重启后会自动按照”1>4″依次选择相应的菜单项。验证成功
选择2.6.34版本内核重启系统后,执行命令:
# uname -r
可以查看系统当前所用内核的版本。