本文发自 http://www.binss.me/blog/how-to-compile-and-install-linux-kernel/,转载请注明出处。
最近在折腾KVM,频繁更换kernel,在此记录下对kernel进行编译和安装的过程:
环境是Ubuntu 16.04 LTS。
坑
在编译之前先说说遇到的几个坑:
-
不要在Mac下clone源码
举个栗子,Mac下clone的版本:
ubuntu@ubuntu-xenial:/vagrant/KVM-Learning/include/uapi/linux/netfilter_ipv4$ ll total 36 drwxr-xr-x 1 ubuntu ubuntu 340 Dec 2 09:39 ./ drwxr-xr-x 1 ubuntu ubuntu 16320 Dec 3 13:30 ../ -rw-r--r-- 1 ubuntu ubuntu 6659 Dec 2 09:39 ip_tables.h -rw-r--r-- 1 ubuntu ubuntu 362 Dec 2 09:39 ipt_ah.h -rw-r--r-- 1 ubuntu ubuntu 758 Dec 2 09:39 ipt_CLUSTERIP.h -rw-r--r-- 1 ubuntu ubuntu 368 Dec 2 09:39 ipt_ecn.h -rw-r--r-- 1 ubuntu ubuntu 659 Dec 2 09:39 ipt_LOG.h -rw-r--r-- 1 ubuntu ubuntu 405 Dec 2 09:39 ipt_REJECT.h -rw-r--r-- 1 ubuntu ubuntu 368 Dec 2 09:39 ipt_ttl.h -rw-r--r-- 1 ubuntu ubuntu 234 Dec 2 09:39 Kbuild
Linux下clone的版本:
ubuntu@ubuntu-xenial:~/KVM-Learning/include/uapi/linux/netfilter_ipv4$ ll total 68 drwxrwxr-x 2 ubuntu ubuntu 4096 Dec 3 13:52 ./ drwxrwxr-x 27 ubuntu ubuntu 20480 Dec 3 13:52 ../ -rw-rw-r-- 1 ubuntu ubuntu 6659 Dec 3 13:52 ip_tables.h -rw-rw-r-- 1 ubuntu ubuntu 362 Dec 3 13:52 ipt_ah.h -rw-rw-r-- 1 ubuntu ubuntu 758 Dec 3 13:52 ipt_CLUSTERIP.h -rw-rw-r-- 1 ubuntu ubuntu 368 Dec 3 13:52 ipt_ecn.h -rw-rw-r-- 1 ubuntu ubuntu 838 Dec 3 13:52 ipt_ECN.h -rw-rw-r-- 1 ubuntu ubuntu 659 Dec 3 13:52 ipt_LOG.h -rw-rw-r-- 1 ubuntu ubuntu 405 Dec 3 13:52 ipt_REJECT.h -rw-rw-r-- 1 ubuntu ubuntu 368 Dec 3 13:52 ipt_ttl.h -rw-rw-r-- 1 ubuntu ubuntu 312 Dec 3 13:52 ipt_TTL.h -rw-rw-r-- 1 ubuntu ubuntu 234 Dec 3 13:52 Kbuild
可以发现Mac下clone的版本只有ipt_ecn.h,而Liunx下clone的版本有在ipt_ecn.h和ipt_ECN.h。为什么呢?因为Mac OS不区别文件名大小写,因此在ipt_ecn.h和ipt_ECN.h中只保留了ipt_ecn.h一个文件,因此在编译时自然就因为缺文件而出错了:
cc1: some warnings being treated as errors scripts/Makefile.build:295: recipe for target 'net/ipv4/netfilter/ipt_ECN.o' failed make[3]: *** [net/ipv4/netfilter/ipt_ECN.o] Error 1 scripts/Makefile.build:440: recipe for target 'net/ipv4/netfilter' failed make[2]: *** [net/ipv4/netfilter] Error 2 scripts/Makefile.build:440: recipe for target 'net/ipv4' failed make[1]: *** [net/ipv4] Error 2 Makefile:968: recipe for target 'net' failed make: *** [net] Error 2
-
clone中断
由于Linux kernel代码巨达2G,而git clone又不支持断点续传,再加上墙的干扰,如果能一次成功clone完,只能说你的运气不错。
如果你像我一样运气不太好,建议使用两阶段clone法,首先clone最后一个commit,成功后再把历史fetch下来:
$ git clone --depth=1 $ git fetch --unshallow
如果你比我还背,建议使用海外VPS将代码clone下来,然后zip后下载到本地。
-
编译前确保硬盘有足够的空间
编译后du了文件夹,足足有15G。如果在编译的过程中硬盘满了,就会抛出奇奇怪怪的错误。由于我用的是VitualBox虚拟机,因此最好的建立时就把磁盘扩充到50G:
在VirtualBox中右键虚拟机,Show in Finder,可以打开虚拟机的镜像文件夹,cd到该目录,执行以下命令:
VBoxManage clonehd ubuntu-xenial-16.04-cloudimg.vmdk ubuntu-xenial-16.04-cloudimg.vdi --format vdi VBoxManage modifyhd ubuntu-xenial-16.04-cloudimg.vdi --resize 51200
在VirtualBox中选中虚拟机,Settings-Storage,选中SCSI Port 0,点击右边按钮,Choose Virtual Hard Disk File,选中刚刚新创建的vdi镜像。
启动虚拟机,df可以发现硬盘已被扩充到50G。此后可以删除原来的镜像文件ubuntu-xenial-16.04-cloudimg.vmdk。
基本方法
编译和安装
-
下载源代码
将代码clone下来。
可以选择linus在github维护的最新版:https://github.com/torvalds/linux.git
由于希望能够选择一个稳定的版本,因此选择了从stable分支中的4.8.10版本作为编译和研究的对象:GitHub - GiantVM/KVM-Learning
git clone https://github.com/GiantVM/KVM-Learning
-
编译环境
我选择Ubuntu 16.04。
安装必要的软件包:
sudo apt-get install build-essential libssl-dev ncurses-dev xz-utils kernel-package
-
配置
通过
make config
一步步配置kernel参数,或者选择偷懒,直接拷贝当前kernel的配置:cp /boot/config-4.4.0-51-generic .config make menuconfig
或者更加方便:
make localmodconfig
-
编译
make
为了提升编译速度,如果有多核处理器,建议使用-j参数增加并行编译的任务数。比如开48个核,只需两分钟就能编译完哟。
make -j 48
-
安装
安装模块
make modules_install
安装内核
make install
为了避免神秘panic,来到
/boot
下找到新安装的kernel名称,然后手动update-initramfs:update-initramfs -c -k 4.8.10+ update-grub2
单独编译模块
这里以编译kvm为例:
-
编译
make clean CONFIG_KVM=m CONFIG_INTEL_KVM=m -C /home/binss/Desktop/KVM-Learning M=/home/binss/Desktop/KVM-Learning/arch/x86/kvm make CONFIG_KVM=m CONFIG_INTEL_KVM=m -C /home/binss/Desktop/KVM-Learning M=/home/binss/Desktop/KVM-Learning/arch/x86/kvm -j 4
-
复制 在/home/binss/work/KVM-Learning/arch/x86/kvm将生成kvm.ko和kvm-intel.ko两个模块,将其复制到/lib/modules/$(uname -r)/kernel/arch/x86/kvm目录下。
cp kvm.ko /lib/modules/$(uname -r)/kernel/arch/x86/kvm cp kvm-intel.ko /lib/modules/$(uname -r)/kernel/arch/x86/kvm
-
安装
depmod -a
重新配置模块依赖关系。
modprobe kvm modprobe kvm_intel
加载两个模块。
或直接通过make modules:
make modules SUBDIRS=/home/binss/Desktop/KVM-Learning/arch/x86/kvm
make modules_install SUBDIRS=/home/binss/Desktop/KVM-Learning/arch/x86/kvm
移除
make install一时爽,移除就比较麻烦了,需要手动删除以下目录的文件(以kernel 4.8.10为例),需要root权限:
rm /boot/vmlinuz-4.8.10
rm /boot/initrd.img-4.8.10
rm /boot/System.map-4.8.10
rm /boot/config-4.8.10
rm -rf /lib/modules/4.8.10/
rm /var/lib/initramfs-tools/4.8.10/
删除完后更新grub:
update-grub2
Debian大法
使用前面的方法编译并安装kernel并reboot后,我悲剧地panic了。只能切回原来的kernel进入系统。
2017.04.17 已解决并更新文章,请放心使用以上方法
由于我的环境是Ubuntu,所以考虑使用debian大法,即使用make-kpkg来编译kernel,它是debian系提供的一套编译并打包kernel的脚本,见:
https://debian-handbook.info/browse/squeeze/sect.kernel-compilation.html
优点
- 使用fakeroot编译,无需放到
/usr/src/linux/
下以root权限进行编译。 - 稳定,基本不会有panic的悲剧发生。
- 方便,通过dpkg进行安装和管理,删除只需一行命令。
编译和安装
-
配置
fakeroot make-kpkg --config
-
清理
如果之前编译过,这次想编译版本号不同的kernel,建议先清理下:
fakeroot make-kpkg clean
-
编译
fakeroot make-kpkg --append-to-version=test kernel_image kernel_headers --initrd -j 48
- kernel-image 生成kernel和modules。
- kernel-doc 生成kernel相应的文档。
- kernel-headers 生成kernel的header files。
- kernel-source 生成kernel相应的源代码。
参数
- --config 手动指定配置文件
- --initrd 生成initramfs
- --revision 指定版本号。需要以数字开头,即上面的1.0.0BINSS和1。
- -j 编译路数,CPU core越多开越高速度越快。
- --append-to-version
为原kernel新增后缀。如
--append-to-version -kvm
由linux-image-4.8.10生成linux-image-4.8.10-kvm:ii linux-image-4.8.10 1.0.BINSS amd64 Linux kernel binary image for version 4.8.10 ii linux-image-4.8.10-kvm 1 amd64 Linux kernel binary image for version 4.8.10-kvm
-
安装
编译完成后,在上级目录生成linux-image-4.8.10_1.0.BINSS_amd64.deb和linux-headers-4.8.10_1.0.BINSS_amd64.deb,安装即可:
sudo dpkg -i linux-headers-4.8.10_1.0.BINSS_amd64.deb sudo dpkg -i linux-image-4.8.10_1.0.BINSS_amd64.deb
打patch
fakeroot make-kpkg clean
zcat /usr/src/kernel-patches/diffs/grsecurity2/grsecurity-2.1.14-2.6.32.13-201005151340.patch.gz | patch -p1
fakeroot make-kpkg --append-to-version -grsec --revision 1 --initrd kernel-image
移除
先看看装了哪些kernel包:
dpkg --list | grep linux-image
卸载之
sudo apt-get purge linux-image-4.8.10
也可以通过GUI工具Synaptic进行卸载。
卸载后更新grub:
update-grub2
直接下载安装
当然,如果对kernel没有什么自定义配置,使用别人编译好的kernel是最吼的:
到这个网站下载需要的kernel: http://kernel.ubuntu.com/~kernel-ppa/mainline
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.2/linux-headers-4.9.2-040902_4.9.2-040902.201701090331_all.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.2/linux-headers-4.9.2-040902-generic_4.9.2-040902.201701090331_amd64.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.2/linux-image-4.9.2-040902-generic_4.9.2-040902.201701090331_amd64.deb
安装:
sudo dpkg -i *.deb
1F ……mac 文件系统默认区分大小写 6 years, 10 months ago 回复
可以选择不区分大小写,默认是区分大小写的