¶ 下载内核
一般下载tarball,也就是.tar.xz格式的源码包。如果/
够大,可以直接解压到/usr/src
,也可以解压到机械盘上。
¶ 配置
¶ .config
里面是一些flag,内核编译的时候会读取这个文件,根据这些flag来配置。
常用的有:
- CONFIG_LOCALVERSION
附加在在内核的version
string后面。自动生成的通常默认是-amd64-desktop+
,生成的内核版本类似于5.1.0-amd64-desktop+
。设置CONFIG_LOCALVERSION="-default-config"
后,编译生成的内核版本号就是类似于5.1.0-default-config
。来源:https://stackoverflow.com/questions/28684811/how-to-change-version-string-of-the-kernel
¶ make menuconfig
如果手动编辑了.config
的话,这一步可能会根据手动编辑的内容调整一些其他选项,比如如果设置了CONFIG_KASAN=y
,执行make menuconfig
后会自动加上CONFIG_KASAN_GENERIC=y
和CONFIG_KASAN_OUTLINE=y
。
sudo apt install -y flex bison libelf-dev |
如果没有特殊需求,可以直接按右键头选中Exit
然后按enter,选保存即可。
也可以在里面更改一些内核配置,常见的:
¶ KASAN
KASAN是一个动态检测内存错误的工具:在Linux内核使用Kasan
对应.config
里的:
CONFIG_SLUB_DEBUG=y |
CONFIG_KASAN_OUTLINE=y
生成的二进制文件更小,而CONFIG_KASAN_INLINE=y
更快。
参考:https://www.kernel.org/doc/html/v5.1/dev-tools/kasan.html
¶ kobject debugging
kobject debugging
kobject release debugging
这俩开了之后dmesg里有意义不明的输出。
¶ make
多线程编译
make -j$(nproc) > /dev/null |
> /dev/null
是为了防止warning和error被刷掉,比如让我们装libelf-dev
的警告。
¶ 安装到系统目录
¶ 内核模块
如果没有特殊需求,一般可以把内核模块的debug信息给去掉,节约安装空间。
make INSTALL_MOD_STRIP=1 modules_install > /dev/null |
注意对于centos不能INSTALL_MOD_STRIP=1
,不然启动貌似会出问题。应该
make modules_install |
然后再用这里的方法去/usr/lib/modules
里手动把debug信息去掉:
¶ 内核
make install |
如果有类似于这样的报错:
没有规则可制作目标“certs/rhel.pem”,由“certs/x509_certificate_list” 需求。 |
那可能要把.config
里的CONFIG_SYSTEM_TRUSTED_KEYS
后面引号里的东西删掉。
另外要注意看看有没有要我们安装console-setup
和plymouth-themes
的提示。
参考:make[1]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。
¶ (可选)用于编译内核模块的文件
这个安装的头文件只能给用户态程序用,不能用于编译内核模块:
make INSTALL_HDR_PATH=$target_dir headers_install |
如果用包管理器安装linux-headers-xxx
的话,会把头文件安装在/usr/src/linux-headers-xxx-amd64
和/usr/src/linux-headers-xxx-common
下面,里面有用的只有这几个文件或文件夹:
arch/x86/include/ arch/x86/Makefile* include/ Makefile Module.symvers scripts/ tools/ |
所以如果要安装用于编译内核模块的文件到系统目录,只需要把这些文件或文件夹放进/usr/src/linux-headers-我们编译的内核版本
即可。
之前安装的内核模块的目录/usr/lib/modules/我们编译的内核版本
里的build
和source
符号链接原先是指向编译时使用的源码的路径,现在改到/usr/src/linux-headers-我们编译的内核版本/
即可。
¶ 安装到指定目录
这样可以在服务器上编译内核,安装到$target_dir
,然后$target_dir
打包传到目标机器,再安装到目标机器上的系统目录即可。
¶ 内核模块
把内核模块安装到$target_dir/lib/modules/$kernel_version_to_install
:
INSTALL_MOD_PATH=$target_dir make modules_install |
¶ 内核
把System.map-$kernel_version_to_install
和vmlinuz-$kernel_version_to_install
安装到$target_dir
下面:
INSTALL_PATH=$target_dir make install |
会报错:
ln: 无法创建符号链接'/boot/System.map': 权限不够 |
不用管这个报错,因为我们不安装到系统目录。
¶ (可选)内核配置
把config-$kernel_version_to_install
安装到$target_dir
下:
kernel_version_to_install=$(make kernelrelease) |
¶ (可选)用于编译内核模块的文件
把这些文件安装到$target_dir/linux-headers-$kernel_version_to_install
:
kernel_version_to_install=$(make kernelrelease) |
¶ 在目标机器上安装到系统目录
在编译服务器上把$target_dir
压缩,传输到目标机器上,解压出来,进入$target_dir
,然后执行以下指令来安装到目标机器上的系统目录里:
kernel_version_to_install=$(ls lib/modules/) |
然后给刚刚安装的内核生成initramfs:Linux生成initramfs
¶ 更新grub
如果电脑上装了多个linux,那选系统界面的grub可能不是当前系统提供的,这个时候就要去提供grub的那个系统更新grub才行。
¶ Debian系
sudo update-grub |
¶ CentOS
Legacy启动 |
CentOS的启动内核是通过grubby设置的,所以CentOS的grub2-mkconfig
可能只会输出发现的其他操作系统的启动项,比如只输出Windows
:
Generating grub configuration file ... |
但是其实也同时把当前操作系统的内核给识别出来了。
¶ 设置默认内核
¶ grubby
CentOS使用grubby来管理启动项,因此需要使用grubby来设置默认内核。首先添加内核:
sudo grubby --add-kernel=/boot/vmlinuz-xxxx --title="随便写点啥" |
注意还需要用grub2-mkconfig更新一下grub.cfg,新加的内核的args和root才会正常。
然后设置为默认内核:
sudo grubby --set-default=/boot/vmlinuz-xxxx |
其他实用grubby子命令:
查看grubby列表中的所有内核 |
参考:https://www.golinuxcloud.com/grubby-command-examples/
¶ 设置GRUB默认项
如果可以与GRUB菜单交互,那么也可以这样:GRUB菜单记住上次的选择的内核