从零开始构建linux(一)——编译linux内核
通常说起linux,脑子里就会想到ubuntu、debian、suse等等著名的发行版。然而,这些发行版的体积太过庞大,很多功能从来都用不着。对于有洁癖的人——比如我——总是想自己裁剪内核和外围的应用程序,制作自己的linux系统。
其实自己制作linux系统并不是一件很复杂的事情,只可惜网上的各种资料良莠不齐,我经过了各种试验,把各篇教程结合在一起看,终于成功了。
本着循序渐进的原则,本篇博客分为多个试验阶段。
============阶段一:安装宿主机CentOS==============
为了方便在做试验时上网查资料,我决定在虚拟机中做试验。首先得在虚拟机中安装一个功能较为齐全的linux,用它来编译linux内核、busybox,以及制作initrd和根文件系统等。
我选用VirtualBox虚拟机。在VirtualBox中创建一个名为diylinux的虚拟机,内存大小1024MB,一个固定大小的8GB硬盘,开启PAE/NX(设置->系统->处理器->扩展特性)。在虚拟机的存储->IDE控制器中加入一个光驱,放入#HREF"http://pan.baidu.com/s/1slEDAKd"#-HREF1CentOS-6.6-i386-minimal.iso#-HREF2,启动虚拟机。
启动后画面如下,选择第二个选项Install system with basic video driver
1.jpg
出现Disc Found对话框后,选择Skip。选择简体中文后Next,在键盘布局那里用默认的“美国英语式”后Next,在存储设备那里选择第一个“基本存储设备”然后Next,主机名保持默认后Next,时区默认上海后Next,根密码输入123456后Next。然后就是安装方式,选择最后一个“创建自定义布局”后Next。简单起见,我把8GB的硬盘分成一个ext3分区用了挂着/,和一个象征性的swap分区,然后Next,如图:
2.jpg
然后在安装引导程序的页面点击最后一个Next,CentOS6即开始安装,如图:
3.jpg
进入系统后,输入账号root,密码123456,即可登录系统,如图:
4.jpg
===============阶段二:编译linux内核===============
宿主机搭建好了,那么就要开始编译linux内核了。这个linux内核就是给我们自己搭建的linux使用的。
首先要下载内核源码。我使用最经典的linux 2.6版本。
由于CentOS默认没有开启网卡,所以需要手动开启一下:
+++code
ifup eth0
---code
由于下载源码用到工具wget,所以先安装一下wget:
+++code
yum install wget
---code
然后用wget下载linux 2.6的内核源码包:
+++code
cd ~
wget http://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.32/linux-2.6.32.67.tar.xz
---code
下载完以后,在~下就有了linux-2.6.32.67.tar.xz。由于是xz格式,所以tar命令暂时无法解开,需要先安装xz命令:
+++code
yum install xz
---code
然后解压:
+++code
tar xvf linux-2.6.32.67.tar.xz
---code
这是就有了linux-2.6.32.67目录,进入之:
+++code
cd linux-2.6.32.67
---code
由于配置编译选项时,会用到gcc和ncurses库,所以先安装gcc和ncurses:
+++code
yum install gcc
yum install ncurses-devel
---code
进入目录后即可开始配置编译选项:
+++code
make i386_defconfig
make menuconfig
---code
make menuconfig会出现一个窗口如图:
5.jpg
为了节约编译时间和降低调试的复杂度,把第二项Enable Loadable module support取消掉,把Networking support取消掉,然后Exit。
由于编译过程中需要用到perl,所以再安装perl:
+++code
yum install perl-devel
---code
最后即可开始编译:
+++code
make bzImage
---code
在漫长的等待之后,最终看见如下的画面:
6.jpg
注意其中的“Kernel: arch/x86/boot/bzImage is ready”,这个bzImage就是我们要的内核。
把这个内核复杂到~目录下备用:
+++code
cp arch/x86/boot/bzImage ~
---code
可以看一个这个bzImage的属性:
+++code
cd ~
file bzImage
---code
有如下字样“bzImage: Linux kernel x86 boot executable bzImage,version 2.6.32.67”,说明对了。
=================阶段三:编译busybox===================
光光有了linux内核而没有外围的应用程序是远远不够的,没有什么作用。最基本的应用程序就是各种linux命令,比如echo、ls、cat、ifconfig等等。在各种发行版中,每一个命令都是一个独立的应用程序。如果要自己一个个编译这些程序并布置好,那实在是太劳心了。好在有busybox这个神奇的工具。这个工具实现了一百多个常用命令的功能,而且使用上和独立的命令没有任何区别。
它的原理是这样的:首先由一个名叫busybox的可执行文件,然后在/bin和/sbin下面创建很多指向busybox的软链接,比如/bin/echo -> busybox,/bin/ls -> busybox等等。当在shell中输入echo “hello”时,事实上内核执行的是busybox。那么问题就来了:busybox是怎么知道要执行echo的功能而不是ls的功能呢?其实很简单。用C语言写过复杂一点的程序的人应该知道,main函数是带参数的,即int main(int argc,char* argv[]),而argv[0]即为shell中输入的命令。所以通过解析argv[0]即可得知是那个命令了。
首先要下载busybox的源码包:
+++code
cd ~
wget http://busybox.net/downloads/busybox-1.20.2.tar.bz2
---code
然后在~目录下就有了busybox-1.20.2.tar.bz2,解压:
+++code
tar xvf busybox-1.20.2.tar.bz2
---code
这时就有了busybox-1.20.2目录了,进入目录并开始配置编译选项:
+++code
cd busybox-1.20.2
make defconfig
make menuconfig
---code
在Busybox Settings —>Build Options下的第一个选项Build BusyBox as a static binary(no shared libs)选上。因为我们的linux环境暂时还没有加入各种运行时库,所以必须静态链接。
由于需要静态链接,所以我们的glibc必须有一个静态的版本,而当前系统是没有的,所以应该先安装一个:
+++code
yum install glibc-static
---code
然后可以开始编译了:
+++code
make
make install
---code
在片刻的等待之后,编译完成,ls一下会发现多了一个_install目录,进去看一下都是一些什么:
+++code
cd _install
ls
---code
7.jpg
里面是bin、sbin和usr,是不是很像linux的根目录了?是的,我们就是要用它来构建linux的根目录。
至此busybox也编译完了。
===================阶段四:无盘linux的运行===============
离成功不远了。现在我们要开始制作一个在仅在内存中运行的linux,这个linux在运行时不访问硬盘。哈哈,是不是想到能够做一个liveCD或U盘系统呀?
首先,在~目录下建一个文件夹名为rootfs,它是我们用来构建根目录的地方。然后把busybox下的那个_install目录中的内容全部复制到rootfs中:
+++code
cd ~
mkdir rootfs
cp -r busybox-1.20.2/_install/* rootfs
cd rootfs
---code
现在rootfs下已经有了bin、sbin、usr目录,好像还缺什么。现在来添加:
+++code
mkdir proc mnt var tmp dev sys etc
---code
同时在rootfs下还必须要有一个init文件,这个init文件可以是一个可执行的二进制文件,也可以是一个shell脚本,或者是指向前面两者的链接。init文件会在linux内核初始化就绪后被执行。方便起见,我们就把init做成一个指向bin/sh的软连接:
+++code
ln -s bin/sh init
---code
dev目录下还必须有几个必要的设备console,null,tty,tty1,tty2,tty3,tty4:
+++code
cd dev
mknod console c 5 1
mknod null c 1 3
mknod tty c 5 0
mknod tty1 c 4 1
mknod tty2 c 4 2
mknod tty3 c 4 3
mknod tty4 c 4 4
---code
这些tty就是和用户交互的终端。
好了,适用于一个内存linux的根文件系统就做好了,现在来制成一个压缩镜像吧:
+++code
cd ~/rootfs
find . | cpio -H newc -o > ../rootfs.img
cd ../
gzip rootfs.img -f
---code
现在~目录下就有bzImage与rootfs.img.gz了:
8.jpg
把这两个文件复制到/boot目录下,然后打开vi编辑/boot/grub/grub.conf:
+++code
cp bzImage rootfs.img.gz /boot
vi /boot/grub/grub.conf
---code
在/boot/grub/grub.conf的末尾添加入:
+++code
title diylinux
	root (hd0,0)
	kernel /boot/bzImage rw root=/dev/ram
	initrd /boot/rootfs.img.gz
---code
然后重启,在BIOS之后会看到启动画面:
9.jpg
此时要按任意键唤出选项:
10.jpg
要记得选择diylinux选项,然后将进入我们自制的linux的启动过程了。显示一大堆启动信息,然后画面定格:
11.jpg
可不要以为这个是死机了。请仔细看最后一句话“Please press enter to activate this console”,意思是说,让你按一下回车键,就可以激活控制台啦。按下回车后,出现了命令提示符”#”,此时可以输入各种命令啦。如图:
12.jpg