首页 > 代码库 > Linux内核编译及系统裁剪之一
Linux内核编译及系统裁剪之一
Linux内核编译方法详解及系统裁剪之一详解
我们的内核是由两部分组成的:
1,内核核心
核心文件的路径是/boot/vmlinuz-内核版本号
如下图->
2,内核模块(ko:kernel object,内核对象)
ko文件的路径是/lib/modules/内核版本号/下的所有文件
如下图->
我们的内核有两种设计风格:
1,单内核设计风格
Linux的内核就属于是单内核设计风格的,不过Linux的单内核设计风格采用了微内核设计风格的模块化设计思想,所以使得我们的Linux内核的核心可以被设计的很小,而内核所需要提供的其他功能都被设计成了各种内核模块,需要的时候只需将各种内核模块加载进内核的核心即可
2,微内核的设计风格
Linux内核的官方网站是www.kernel.org
如下图->
上图中的:
mainline表示主线内核版本
longterm表示长期维护的内核版本
假如我们当前系统的Linux内核的版本号是2.6.17:
2表示主版本号
6表示次版本号
17表示修正号
我们的Linux的2.4系列版本的内核有一个特性,如果次版本号为奇数则表示该内核版本为测试版或者开发版(比如2.5系列的内核版本),次版本号为偶数则表示该内核版本为稳定版(比如我们的2.4系列的内核版本),但是从2.6系列版本的Linux内核开始就不是这样来区分内核版本了,从2.6系列版本的Linux内核开始,每个版本的Linux内核都会同时被维护两个分支,如下图->
比如说我们出来一个稳定版本的内核之后,比如说上图中的2.6.17这个版本,接下来的版本会在此版本下出现两个分支:
其中一个分支会对内核版本号的修正号进行升级,上图中的rc就表示处于修正阶段,rc阶段的分支一般是在接下来的新版本中添加一些新特性、新功能等等,比如说新添加了一个驱动程序,然后会测试该驱动程序是否稳定,当在接下来的新版本中如果测试该驱动稳定了,比如说是在上图中的rc5这个版本测试稳定了,那么rc5这个版本接下来的版本就是新一代的稳定版,比如就是上图中的2.6.18版本,然后接着重复上述的过程
另一个分支被称为稳定阶段,上图中的稳定阶段的第一个版本是2.6.17.1,接下来的稳定阶段的版本号以此类推,我们稳定阶段的内核版本号的第四段也被称为是次修正号,稳定阶段内核版本每一次修正表示可能修复了旧版本的一些bug
·装载内核模块的命令
1,insmod命令
2,modprobe命令
当内核编译完成之后,或者说是我们的系统安装完成之后,内核的核心文件就位于我们的文件系统的/boot下的以vmlinuz-内核版本号命名的文件,这个版本号也被我们称作是rpm包的发型号,查看当前系统内核版本号的命令是uname -r,如下图->
我们的内核进程虽然是运行在内存空间中的内核空间,但是我们的用户空间是可以和我们的内核进程通信的,用户空间是通过/proc和/sys目录来访问和监控内核的:
1,/proc
该目录下的大部分文件都是只读的,如下图->
除了/proc/sys这个目录下的子子目录中的文件,这些文件对系统管理员来说大部分都是可读写的,如下图->
那就意味着我们的管理员可以通过修改这些文件的内容来修改我们内核的运行特性,这些文件的内容大部分都是内核的参数,所以说修改了这些文件之后就可以修改我们内核的工作特性,比如说一个叫做swappiness文件,该参数表示是否启用交换空间或者是在多大程度上倾向于使用交换空间,如下图->
还有一个叫做drop_caches的内核参数,如下图->
我们可以使用free -m命令来显示内存中的cached和buffers的相关信息,如果我们不想将这两个信息显示出来,就可以通过修改drop_caches这个参数来实现,但是由于这些内核参数实质上并不是文件,所以我们想要修改它们的参数的时候并不能使用vim,如下图->
而只能使用echo重定向的方式来修改内核参数的内容,如下图->
由上图知,将内核参数drop_caches修改为1表示清空buffers的显示信息
2,/sys
该目录下,某些文件也是可写的
这两个目录是我们的用户空间和内核交互的机制,而交互的时候,是我们的用户在用户空间通过一些命令来修改内核的特性来实现的,修改内核的方式就是通过修改/proc或者/sys目录下的某个文件的内容来实现的,/proc和/sys被称为伪文件系统,因为这两个目录下的文件都不是真实存在的,这些文件通常都是内核中的某个参数
·设定内核参数值的方法
1,echo VALUE > /proc/sys/TO/SOMEFILE
不同的内核参数所可以接收的值是不一样的,像我们刚刚提到的drop_caches这个参数只接收0,1,2这三个值,又比如我们在/proc/sys/kernel目录下有一个叫做hostname的内核参数,这个内核参数保存的是我们当前主机的主机名,我们直接使用echo的方法就可以改变我们的主机名,如下图->
2,sysctl命令
该命令是专门用于改变/proc/sys目录下内核参数的值的命令
-w选项可以设定内核参数的值,而且在使用该选项指定内核参数的时候还可以省略/proc/sys这个上层目录,直接使用内核参数的父目录和内核参数即可,并且内核参数和它的父目录之间的分隔符不是/而是.,用法格式:
比如说我们要改变当前主机的主机名,直接使用:
sysctl -w kernel.hostname="主机名" 即可
如下图->
-a选项表示显示当前系统上所有的内核参数和它们的值,如下图->
我们常用的内核参数就是drop_caches、hostname以及ipforward这三个,以上两种修改内核参数的方法在重启系统之后都会失效,因为我们的内核进程从系统启动到关闭系统的这个过程中都是在内存空间中运行的,所以我们所有对内核所做的修改结果都是保存在内存中的,所以说修改的结果可以立即生效,但是不可以永久有效,要想永久有效,就得去编辑/etc/sysctl.conf这个文件,但是不能立即生效,要想使得我们在该文件中编辑的内容可以立即生效的话,在编辑完该文件之后使用sysctl -p命令即可,该命令可以通知我们的内核去重新读取/etc/sysctl.conf这个文件来重新设定内核的参数,我们的系统启动服务脚本rc.sysinit会在启动系统的时候去读取/etc/sysctl.conf这个文件中的内核配置信息,来设定我们的内核参数,比如我们的/proc/sys/net/ipv4/ip_forward这个内核参数,我们的操作系统是允许在两块网卡之间转发数据包的,这样一来就可以把我们的主机当做路由器来使用,这就是ip_forward这个参数的功能,该参数的值0表示禁用此功能,1表示启用此功能,我们可以在/etc/sysctl.conf这个文件中来编辑此项功能,编辑的格式如下:
参数父目录.参数=值
/proc/sys这个上层目录可以省略,如下图->
·内核模块的管理
1,lsmod命令
该命令可以查看我们当前系统装载了哪些内核模块,如下图->
由上图可知,该命令可以列出我们系统上ko文件的名称,大小以及被谁调用了调用了几次等等,所以该命令可以显示三个字段Module、Size以及Used by,每一个模块分别对应了内核中的每一个功能,比如ext3表示的是支持ext3文件系统功能的模块,dm开头的模块表示和device mapper功能相关的模块,cdrom表示和光驱的驱动程序相关的模块,snd_ac97_codec是和我们声卡驱动程序相关的模块,pcnet32是和我们网卡的驱动程序相关的模块,这个网卡设备是由Vmware虚拟出来的网卡,Vmware虚拟出来的网络设备都是pcnet32的。
2,modprobe命令
mod表示模块,probe表示探测,该命令可以实现装载某个内核模块
用法:modprobe MOD_NAME,modprobe命令在使用的时候只需要指定模块名,而不需要指定模块的具体路径
-r选项表示卸载对应模块
3,modinfo命令
该命令用来查看模块的具体信息
用法:modinfo MOD_NAME
由上图知,该命令所显示的信息有:
->filename表示该文件所在的文件路径
->module_sig表示模块的签名
->parm表示该模块可以接受的各种参数
->depends表示该模块所依赖的模块
->license表示的是许可证
->description表示的是描述信息
4,insmod命令
这也是一个装载模块的命令
用法:insmod /PATH/TO/SOMEFILE,该命令在装载模块的时候和modprobe不一样,它的后面必须跟上所要装载的ko文件的具体路径
5,rmmod命令
该命令也是用来移除模块的,但是具体的用法和modprobe -r命令是一样的,后面直接跟上对应的模块名称即可
用法:rmmod MOD_NAME
6,depmod命令
我们的ko文件之间互相是有依赖关系的,这个依赖关系表我们可以使用该命令手动生成
用法:depmod /PATH/TO/MODULES_DIR
该命令可以帮助我们生成模块间的依赖关系,而且生成的依赖关系文件可以保存在对应模块的目录中
在Linux系统中众多的驱动程序其实都是内核中的模块,在内核上编译的驱动程序必须和内核的版本一致。
对于内核来讲,除了内核中最核心的功能必须编译进内核之外,其余所有功能在编译的时候都有三种选择:
1,不使用此功能,即不编译
2,编译成内核模块
3,和内核编译到一起
·如何手动编译内核
红帽Linux操作系统有一个特性,无论系统的发行版如何升级,内核的版本号都不会改变。
编译内核的前提,首先得安装编译工具和编译环境,我们可以首先使用yum grouplist命令来查看development tools和development libraries这两个包有没有安装,如下图->
我们由上图发现,没有安装development libraries,我们可以使用yum groupinstall来安装,如下图->
显示已经将该环境安装,安装完成之后我们就要开始下载内核了,我们下载的内核的版本是2.6.28.7,如下图->
一般来说,我们Linux的内核的源码是放在/usr/src目录下的,故我们将该压缩包解压至/usr/src目录下即可,如下图->
在实现内核配置的时候,我们有很多种方法,编译内核的方法和编译普通软件的方法是不一样的,因为内核的特性太多了,我们不能单单使用.config来配置,故我们的内核会给我们提供一个专门的界面来帮助我们配置我们内核的特性,选择内核配置的选项有三种:
1,不编译该模块
2,将该模块编译进内核
3,将该模块编译成为ko文件
但是内核提供给我们的可供选择的配置特性有数千种。
我们的操作系统给我们提供了很多种配置内核特性的界面,也有很多种配置内核的特性的选择:
->有默认的配置
->有全选的配置
->还有全不选的配置,表示只编译核心
由上图我们可以知道,我们将内核压缩包在/usr/src目录下解压之后,会生成一个以linux-内核版本号命名的目录,接下来我们要给该目录在/usr/src目录下创建一个软链接,如下图->
然后我们可以发现在该目录下还有很多的子目录,如下图->
比如说arch目录,该目录和我们的CPU平台有关,如下图->
drivers目录和我们的驱动相关,如下图->
crypto目录表示一些加密解密所用的算法模块,如图->
fs目录表示的是文件系统,如下图->
我们的系统给我们提供了两种配置内核特性的方法:
1,图形界面下的配置方法
->make gconfig命令
该命令只能在Gnome桌面环境下使用,即Gnome Software Development
->make kconfig命令
该命令只能在KDE桌面环境下使用,即KDE Software Development
要想使用这两个命令,我们就得安装图形开发库组,这两个命令都非常依赖桌面环境。
2,make menuconfig命令
该命令可以打开一个文本菜单,一个文本环境下的执行窗口,如下图->
注:一定要在内核源码目录下使用该命令!
由上图可知,我们该文本窗口中的很多选项后面都有箭头,这表示该选项下面有很多的子条目,比如说General setup这个选项,如下图->
上图中的选项前面的中括号里面如果是*->表示将该特性编译进内核
M->表示将该功能编译成内核模块
空白->表示禁用该特性
空格键可以在三种选择之间切换
上图中的Local version表示本地版本号,我们使用uname -r命令的时候可以显示我们当前系统的内核版本号,不过版本号后面包括横线的内容都是在Local version这个选项里面编辑的,我们可以在Local version这个选项上敲回车键就可以进行编辑,如下图->
我们在编辑完成之后可以按两下Esc键返回上一层的界面,我们在该界面下编辑完我们的内核特性后的内容会保存在内核源码目录下一个叫做.config的隐藏文件中,如下图->
然后我们对该文件执行make命令就开始编译内核了。
无论是红帽的哪个版本,在/boot下都有一个以config开头的文件,如下图->
该文件表示我们的红帽操作系统在编译内核的时候所使用的配置,如下图->
所以我们可以以该文件为模板,来配置我们的内核特性,这样一来编译内核出错的概率就会小很多,所以通常我们在编译内核的时候都是先把该文件复制到我们要编译内核的源码目录下,命名为.config,所以正常编译内核的流程就是,在将内核压缩包解压之后,将该文件复制到内核源码目录下命名为.config,在此基础上再执行make menuconfig命令,在此基础上修改我们的内核的特性配置,之后编译内核出错的概率就会大大降低,如下图->
之后再执行make menuconfig命令即可,如下图->
上图中的Processor那一行表示我们的处理器类型和特性
红帽为了兼容多种硬件平台,支持很多种硬件的驱动程序,但是这样会使我们的编译速度变得很慢,故我们可以在该选项下只选择我们需要的处理器类型和特性,该选项下的Processor family选项可以选择我们的处理器类型和特性,如下图->
Device Drivers这个选项表示我们的设备驱动,如下图->
该选项里面的很多驱动程序都可以去掉,都是我们用不着的,比如说网卡驱动Network device support,如下图->
我们的网卡驱动中有很多的选项,如下图->
上图中的:
->Ethernet (1000 Mbit)叫做千兆以太网
->Ethernet (10000Mbit)叫做万兆以太网
->Token Ring driver support叫做令牌环网,这个令牌环网也是我们所用不到的
->PCMCIA我们也用不到
->ATM我们用不到
->FDDI我们也用不到
->如果我们是拨号上网的话,那么PPP就可以用到
->SLIP我们也用不到
->万兆以太网我们也用不到
->千兆以太网我们也用不到
->我们可以用到的是10M或100M以太网
->我们的Vmware虚拟机使用的是AMD pcnet32的网络
内核特性配置完成之后,我们就可以对.config文件执行make命令进行编译,然后再执行make modules install命令来安装内核模块,最后再执行make install命令即可,之后我们重启系统就可以在grub界面看到新内核选项的诞生了,这就是编译内核的全部过程。
如果我们想使用远程连接的方法去编译内核得先安装一个叫做screen的软件,该软件可以在我们当前的远程窗口中模拟多个桌面,先安装,如下图->
安装完成之后,我们使用screen就可以新建桌面,就算我们的screen桌面因为某种原因挂掉了,我们还可以还原回来,我们可以使用screen -ls命令来显示已经建立的屏幕,如下图->
我们可以根据被列出来的screen号码使用screen -r screen号码这个命令来将意外中断的screen进行还原,如下图->
所以我们如果要使用远程连接的方式来编译内核的时候建议使用screen窗口来防止我们的远程窗口意外终端导致的内核编译中断,我们可以使用Ctrl+a组合键松开之后按d键模拟中断一个screen窗口,如下图->
exit命令可以退出当前screen。
如果我们的内核在编译好之后,我们又想重新编译的话,我们可以在二次编译前清理此前的编译环境,二次编译清理之前我们得先备份一份.config文件
->然后执行make clean命令
该命令用于清理此前编译好的二进制模块
->再执行make mrproper命令
该命令用于清理此前编译所残留的任何文件,包括.config文件都会被清理掉,所以我们在执行该命令之前一定得将.config文件备份一份,之后再重新编译即可。
注:我们编译的所有操作以及二次编译的所有操作都得在内核源码目录下进行!
·手动生成一个Linux操作系统
我们可以在一块硬盘上安装grub程序,之后借助grub找到kernel文件的位置,内核借助于initrd文件找到我们的rootfs,然后在文件系统里面,我们只需提供一个/sbin/init文件,我们的系统就可以启动起来了,再给文件系统里面提供一个/bin/bash,这样用户就有一个可以和计算机交互的界面了,再在/bin下添加一些必要的命令,这样我们的一个Linux系统就诞生了。
操作步骤:
->在我们的主机上新添加一块20G大小的IDE硬盘,如下图->
->给该磁盘创建分区,如下图->
创建一个20M的主分区,当做/boot所在的分区
再创建一个512M的主分区,当做我们的根分区
->将两个分区格式化成为ext3格式的文件系统,如下图->
->在/mnt下创建两个目录,/mnt/boot和/mnt/sysroot,分别当做我们新系统的/boot分区和根分区的挂载点,如下图->
->将这两个分区分别挂载在对应的挂载点下,如下图->
->在boot分区上使用grub-install命令来安装grub,还得使用--root-directory=boot分区上/boot的父目录,再跟上所要安装grub的具体设备,如下图->
安装完成grub之后就会在我们的/boot下生成一个grub目录,如下图->
->/boot下还得有一个内核文件,该内核文件我们可以采用直接复制的方法复制到/boot下,命名为vmlinuz,如下图->
->initrd文件是在安装操作系统时自动生成的,同样该文件还可以使用命令生成,该命令叫做mkinitrd,命令用法:
mkinitrd initrd文件的路径(initrd文件一般是在/boot下的) 内核的版本号
但是此时我们却不可以这样创建initrd文件,因为我们使用这种方法创建的initrd文件会作用于我们当前的系统,而不是我们将要创建的小系统,不过我们可以使用如下的方法来手动去创建我们的新系统下的initrd文件:
首先使用file命令去查看我们当前系统下initrd文件的类型,如下图->
由上图可知,我们当前系统上的initrd这个文件其实是一个压缩文件
然后,我们将该压缩文件复制到其他目录下进行解压,如下图->
接下来我们再查看解压后文件的类型,会发现解压后的文件是一个cpio文件,如下图->
cpio文件展开后,可能是一堆文件,所以我们可以创建一个目录将展开后的内容全部放至该目录,我们可以使用cpio -id < cpio压缩文件这个命令,来将cpio文件展开至当前目录,如下图->
由上图知,initrd文件实质上就是一个完整的的Linux系统,但是以上展开这个文件的过程实在是太麻烦了,我们可以使用一个更简单的办法,如下图->
只使用一条命就可以完成解压缩归档initrd文件
接下来我们需要来编辑init这个文件,我们使用file命令去查看这个脚本文件的类型,如下图->
由上图知,我们发现该脚本是一个nash脚本,我们使用vim来打开这个脚本文件,打开至文件的最后一行,如下图->
由上图可知,我们发现有一行叫做mkrootdev的内容,这是nash的一个內建命令,表示创建根设备,-t选项表示指定文件系统的类型,我们得将这一行的挂载分区改为/dev/hda2,如下图->
如果我们没有创建swap分区,那么就可以将nash文件里面的resume这一行注释掉,因为这一行内容和我们的swap分区的相关信息有关,如下图->
修改完成之后我们可以将修改后的一堆文件重新打包为initrd,得使用cpio命令进行归档,操作方法:
find . | cpio -H newc(类型) --quiet(指定为静默模式) -o(归档) | gzip -9 > /mnt/boot/initrd.gz,如下图->
到现在我们/mnt/boot下的内核文件有了,initrd文件也有了,grub也安装了,现在就差手动生成grub的配置文件了,我们手动生成即可,如下图->
接下来我们就该编辑我们的根分区了,我们首先得在我们的/mnt/sysroot下创建一个根目录下的常见目录,如下图->
然后再将init这个文件复制到sbin目录下,将bash这个文件复制到我们的bin目录下,之后还要将init和bash文件所依赖的库文件复制到lib目录下,如下图->
复制完成之后我们可以使用chroot命令来测试以下我们新的根文件系统有没有成功,如下图->
最后还得执行sync命令,如下图->
然后我们还得手动去配置init文件的配置文件etc/inittab,如下图->
最后我们要手动生成rc.sysinit这个系统的自启动服务脚本,如下图->
开机后直接打开bash然后再执行sync命令即可
还得给该文件加上执行权限,如下图->
至此我们的新的Linux操作系统就算是搭建完成了,接下来的就是检验我们的这个新的系统能否正常使用即可,如下图->
1,退出新建的根目录
2,将我们当前的系统挂起
3,找到我们新系统所在的磁盘设备的路径
将它作为我们的启动盘,使用Vmware新建一个虚拟机,选择自定义模式->
选择红帽5的操作系统
内存大小设置为32M即可,网络连接方式使用桥接,硬盘选择推荐的LSI,使用已存在的虚拟硬盘,然后找到我们的硬盘路径即可,keep原来的格式,然后我们就可以启动这个虚拟机了
我们的新系统就可以启动了
如果我们希望给我们的新系统的bin目录下添加一些管理系统的命令过去,我们可以将我们的宿主机的/bin下的命令名复制到新系统的bin目录下,再将对应的库文件复制到新系统的lib目录下即可,但是这样一个一个的操作我们所需要的命令会非常的麻烦,我们完全可以使用脚本来完成这整个过程
温故:使用which命令可以查看命令的路径
bash当中有一个特性叫做截取变量的字符串:
格式:1,${parameter#*word}
parameter是一个变量名,word是一个关键字就相当于是一个路径的分隔符,我们截取一个变量内容的字符串是以word为分隔符进行截取:
如果#只出现一次,表示从左至右第一次被word匹配到的字符向左的内容全部截掉->
如果#出现两次,表示从左至右最后一次被word匹配到的字符向左的内容全部截掉->
2,${parameter%word*}
%与#刚好相反,是从右向左截取,*还得写在word的右边
->
·练习:
写一个脚本,要求
给脚本传递一个参数,参数为宿主机的/bin下的命令名,脚本实现将该命令名对应的库文件和命令名同时传递至新系统的对应目录下(如果我们宿主机的库文件在/lib下,那么就得复制到新系统对应的lib目录下,如果宿主机的库文件在/usr/lib下,那么就得复制到新系统对应的usr/lib下,目录一定得对应起来,如果新系统中对应的目录不存在,那么我们就得在新系统中先创建对应的目录,然后再复制相应的库文件,这些都是我们的脚本需要完成的功能)
脚本内容:
脚本执行结果:
我们在启动我们的新系统之前还得复制一个库文件进去,我们在新系统的lib目录下创建一个modules目录,然后复制mii和pcnet32这两个库文件到该目录中去,然后我们期望我们的系统在开机的时候可以自动装载这两个模块,我们可以在rc.sysinit这个系统启动脚本里面进行编辑,使用insmod命令装载这两个模块即可,装载完成之后我们的新系统就可以识别我们计算机上的网卡了,然后我们可以手动给eth0一个地址,再给lo一个地址,最后我们退出新系统的根目录,再开启新系统,最后我们就可以ping我们的网关,看是否可以ping通。
本文出自 “菜鸟的技术文档” 博客,请务必保留此出处http://zhubo.blog.51cto.com/11395641/1867856
Linux内核编译及系统裁剪之一