分类: LINUX
2006-07-13 17:44:33
从源代码打造一个最小化的Linux系统实作指南(转)
选择自 kimsangbaek 的 Blog
以下就是从源代码中打造一个最小化的Linux系统的操作说明.它曾经是《从加电启动到Bash提示符(From PowerUp to Bash Prompt)》的一部分.但是我将它们分离开来,以便使得它们更简短而更为集中化.我们在此所要打造的系统是非常小的,而且并不准备作为工作产品来使 用.如果您想从头开始打造一个有实际用途的系统,请参阅Gerard Beekmans所撰写的 Linux空手道实作指南篇 (Linux From Scratch HOWTO)。
1. 您所需要具备的条件
我们首先要安装一个Linux发行套件比如小红帽(RedHat)到一个分区上,然后使用它来在另一个分区上打造一个新的Linux系统.我将我们所要打 造的系统称为目标系统(target)而把我们所使用来打造新系统的系统称为源头系统(source).可别把这个源头(source)系统同我们同时使 用的源码(source code)相混淆了哦.:)
因此,您得需要一台具有两个独立分区的机器.如果可能,请尽量使用一台没有重要资料在里头的机器,以免数据受损.您可以使用一个已经存在的Linux系统 作为源头系统,但是我并不推荐这种方式.如果您不慎遗漏了我们打造的指令的某些参数,您有可能会意外地在这个系统上安装了一些没有必要的东西,有可能会导 致不兼容和冲突。
旧型的PC机硬件,大部分的486机器或者更早的机型,其BIOS都有一些极其烦人的限制.它们没有办法读取硬盘超过前512兆之后的空间.当然,这个对 于Linux来说并不是什么大问题,因为只要Linux能够引导启动了,将使用Linux自己的磁盘IO,略过BIOS的调用.但是为了能够让这些旧型机 器能够引导Linux,那么Linux内核必须存放在硬盘的前512兆之前的某个位置.如果您正好有这么个旧型机器,您得准备好一个独立的且完全在前 512兆范围内的硬盘分区,并将其挂载为/boot.其它的分区就可以在任何位置,可以任意处理而不必担心是在硬盘的什么位置了。
上一次我打造这个系统时,所使用的源头系统是小红帽6.1(RedHat 6.1),我安装了基本系统,附加有以下软件包∶
* cpp (C++编译器)
* egcs (增强型C编译器)
* egcs-c++ (增强型C++语言编译器)
* patch (打补丁程序)
* make (编译批处理解释器)
* dev86 (设备文件包)
* ncurses-devel (ncurses库开发包)
* glibc-devel (glibc库开发包)
* kernel-headers(内核源码头文件包)
我还安装了X Window视窗系统和Mozilla网络浏览器以便更轻松地阅读文档,而实际上这两个东东并不是必要的.在我竣工之时,这个源头系统大概使用了350兆的磁盘空间(看起来是多了一些,可是我还在纳闷为什么呢)。
竣工之时的目标系统占用了650兆磁盘空间,但是这个数值包含了所有的源码以及中途打造出来的文件.如果空间比较紧凑,您应该在每个软件包都打造完毕之后 执行一下make clean来清除临时文件.当然了,我对这个也是有点吃惊的。
最后,您的准备好我们所要用来打造系统的源码包.这些就是我在本文所讨论的软件包.这些软件包都可以从源码盘里面找到,或者从国际互联网上找到.我会给出美国的站点和位于澳大利亚的镜像站点的地址。
* MAKEDEV (设备生成器包)
美国站点:ftp://tsx-11.mit.edu/pub/linux/sources/sbin
另外一个美国站点:ftp://sunsite.unc.edu/pub/Linux/system/admin
* Lilo (Linux引导器包)
美国站点:
澳大利亚:
* Linux内核包(Kernel) 使用 主页上所列举的镜像站点而最好不要使用美国站点站点下载,因为这些站点通常是超负荷运转的。
美国站点:
澳大利亚站点:
* GNU libc库包 其本身,以及liuxthreads线程附加库可在以下地址下载到∶
美国站点:ftp://ftp.gnu.org/pub/gnu/glibc
澳大利亚站点:ftp://mirror.aarnet.edu.au/pub/gnu/glibc
* GNU libc附加库包 您可能还会需要linuxthreads线程附加库和libcrypt加密附加库.
如果libcrypt没在那个站点找到,那就是因为美国出口法律限制的原因, 那么您就可以从这里弄到libcrypt加密附加库.
通常linuxthreads 线程附加库跟libc库是放在同一个地方的.libcrypt加密附加库:
* GNU ncurses
美国站点:ftp://ftp.gnu.org/gnu/ncurses
澳大利亚站点:ftp://mirror.aarnet.edu.au/pub/gnu/ncurses
* SysVinit (初始化脚本包)
美国站点:ftp://sunsite.unc.edu/pub/Linux/system/daemons/init
澳大利亚:
* GNU Bash (命令解释器包)
美国站点:ftp://ftp.gnu.org/gnu/bash
澳大利亚站点:ftp://mirror.aarnet.edu.au/pub/gnu/bash
* GNU sh-utils (命令解释器工具包)
美国站点:ftp://ftp.gnu.org/gnu/sh-utils
澳大利亚站点:ftp://mirror.aarnet.edu.au/pub/gnu/sh-utils
* util-linux (Linux常用工具包) 本软件包包含有agetty和login。
另外一个站点:ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/
澳大利亚站点:ftp://mirror.aarnet.edu.au/pub/linux/metalab/system/misc
总结一下,您所需要的就是∶
* 一台具有两个分别是400兆和700兆独立分区的机器,或许您可能会需要少一些.。
* 一个Linux发行套件(譬如一个RedHat光盘)和安装方式(譬如一个光驱)
* 以上所列举的源码的tar包。
我假定您可以自己安装源头系统,而用不着我来帮忙.从这里开始,我假定源头系统已经安装好了。
本小项目的第一个里程碑就是使得内核启动起来然后死翘翘,因为它没找到init初始化程序.也就是说我们得安装一个内核和安装lilo.为了顺利安装
lilo,我们要用上在目标系统上/dev目录下的设备文件.lilo需要它们来实现底层必需的磁盘存取来写入引导扇区.MAKEDEV正是用来创建这些
设备文件的脚本程序(您当然可以只需要从源头系统当中复制出来,不过这可是作弊不劳而获哦).但是最重
要的事情就是,我们需要一个文件系统来放置所有的这些东西。
2. 文件系统
我们的新系统是要安装在文件系统上的.因此首先我们得使用命令mke2fs来创建文件系统,然后将其挂载到某个地方.我建议是挂载到 /mnt/target这个目录上.接下来的操作中,我假定就用这个目录了.为了节省您的宝贵时间,您可以在/etc/fstab文件里面添加上这一项, 以便每次源头系统启动的时候就能够自动将这个目录挂载上。
当我们启动了目标系统,放置在/mnt/target上的所有东西就会被当成了放置在/根目录上。
我们需要在目标系统上建立固定的目录结构.请参阅"文件层次结构标准(简称FHS,File Heirarchy Standard)",见于 文件系统一节来了解详情,或者只需要cd切换目录到目标系统所挂载的地方然后尽管执行以下命令∶
mkdir bin boot dev etc home lib mnt root sbin tmp usr var
cd var; mkdir lock log run spool
cd ../usr; mkdir bin include lib local sbin share src
cd share/; mkdir man; cd man
mkdir man1 man2 man3 ... man9
因为FHS标准和大部分的软件包在手册页(man page)放置位置上的处理并不一致,因此我们需要做一个符号连接∶
cd ..; ln -s share/man man
3. MAKEDEV(设备生成器)
我们要把源代码放置到目标系统的/usr/src目录下面.因此,举个例子吧,如果您的目标系统是挂载在/mnt/target这个地方,且您的tar包是放在/root里面,那么您要做的就是∶
cd /mnt/target/usr/src
tar -xzvf /root/MAKEDEV-2.5.tar.gz
然后就把这些tar包复制到您要解开它们的地方就行了.千万别迷糊了哦.;->
当您安装软件的时候,通常情况下您会把它们安装在正在使用的系统上.但是我们并不想这么做,因为我们是要把/mnt/target当做根文件系统 (root filesystem),就是要把这些软件安装到这个地方.不同的软件包有不同的处理方式.比如说MAKEDEV设备生成器包,您要做的是∶
ROOT=/mnt/target make install
您得先在这个包当中的README说明文件和INSTALL安装说明文件当中查出这些选项,或者执行命令./configure --help查看帮助说明。
查看一下MAKEDEV包当中的Makefile文件,看看它是怎样处理我们在命令行当中设置的ROOT变量的.接着通过执行man ./MAKEDEV.man来查看一下它的手册页,看看它是怎么起到作用的.您会发现生成我们自己的设备的方式就是执行cd /mnt/target/dev然后./MAKEDEV generic.请使用ls命令来看看它都为我们生成了哪些设备文件吧。
4. 内核
下一步就是生成内核了.我假设您以前是做过编译内核这种事的,所以我就长话短说了.如果要启动的内核已经准备好的话,那么要安装lilo就会更容易.请返
回到目标系统的usr/src目录,然后在那儿解开Linux内核源码.进入Linux源码树(cd
linux)然后使用您最喜欢的方式配置内核,比如make
menuconfig.如果您想让自己的轻松一些,那么您可以为自己配置一个没有模块的内核.如果您已经
配置了模块,那么您就得编辑Makefile文件,找出INSTALL_MOD_PATH并将其设置为/mnt/target.
现在您可以执行make dep,make bzImage了.如果您设置了模块项,可以再执行make modules,make modules_install.把内核映象文件arch/i386/boot/bzImage和系统函数映象文件System.map复制到目标系统的 boot启动目录/mnt/target/boot下面,然后准备安装系统引导器lilo了。
5. Lilo系统引导器
Lilo包里面带有一个很小巧的脚本,名叫QuickInst.请把lilo源码包解压到目标系统的源代码目录/mnt/target/usr/src下 面,然后执行该脚本,方法是∶ROOT=/mnt/target ./QuickInst.它会询问您一些关于您想怎样安装lilo的问题。
切记∶因为我们已经设置ROOT根系统为目标系统分区了,所以您回答提问时所给出的文件名同它是密切相关的.比如当它询问您默认想启动哪个内核的时候,您 的回答应该是/boot/bzImage,而并不是/mnt/target/boot/bzimage哦.我发现这个脚本里面有个小错误,它会提示说∶
./QuickInst: /boot/bzImage: no such file
但是您甭理这个提示就是了,不会有事的。
我们该让QuickInst把引导扇区(boot
sector)放在何处为妥呢?当我们重启时,我们希望可以选择引导进入源头系统或者目标系统或者其它共存于同一台机器的其它系统.而且我们还希望我们要
使用所编译的lilo来引导我们新系统的内核.我们怎么把这两件事情合而为一呢?让我们先跑一小会儿题,看看lilo在一个双重启动的Linux系统上是
怎样引导DOS的.在这样的一个系统上的lilo.conf文件的
内容看起来可能会跟下面的差不多∶
prompt
timeout = 50
default = linux
image = /boot/bzImage
label = linux
root = /dev/hda1
read-only
other = /dev/hda2
label = dos
如果机器是这么安装起来的,那么主引导记录(MBR,master boot record)就可以被BIOS读取并加载,然后MBR加载lilo启动引导器,而后者则给出一个提示.如果您在提示后面输入dos,lilo就会从 hda2加载引导记录,就加载了DOS。
我们所要做的事情跟上头是一样的,除了在hda2的引导记录应该是另外一个lilo引导记录之外,也就是在QuickInst所询问要安装的那个.因此来 自Linux发行套件的lilo会加载我们所编译安装的lilo,然后我们所编译安装的lilo就会加载我们所编译安装的内核.当您重启后,您会看到两次 lilo的提示。
长话短说,当QuickInst询问您该把引导扇区(boot sector)放到什么地方时,您就回答目标系统所在的分区,比如说是∶/dev/hda2.
现在来修改您的源头系统上的lilo.conf配置文件,那么看起来会有点像这个样子∶
other = /dev/hda2
label = target
修改完毕,接着执行lilo安装LILO.我们应该可以第一个引导进入目标系统了。
6. Glibc库
下一步我们要安装init,但是同运行在Linux上几乎全部的程序一样,init使用了GNU C语言库glibc所提供库函数,因此我们先得把这个东东安装上。
Glibc库是一个很大而且很复杂的软件包.在我那个旧型的带8兆内存的386sx/16机器上,得花掉我90个小时来完成编译工作.但是在我那带有64 兆内存的赛杨(Celeron)433上只花掉了33分钟.如果您只有8兆内存(或者少得让人打颤的容量)的话,那就做好苦熬的准备。
glibc的安装文档建议在不同的独立分离目录里面编译.这样做就能够让您很轻松地再次编译,因为您可以该目录下面接着编译.您可能也会想这么做,因为可以为您节省大约265兆的磁盘空间哦!
跟平常一样,把glibc-2.1.3.tar.gz(或者其它版本)这个tar包解压到/mnt/target/usr/src这个目录下面.接下来, 我们得把附加库也解压到glibc 库目录下面.所以先cd glibc-2.1.3,然后接着在这个目录下面 把glibc-crypt-2.1.3.tar.gz和glibc-linuxthreads-2.1.3.tar.gz这两个tar包解开。
现在我们就可以生成编译目录,设置选项,执行make编译和安装glibc库了.这些都是我所使用过的命令,但是最好您自己阅读一下文档,确认最适合您的 状况的做法.然而在您开始前,您可能需要执行df命令来查看一下还有多少剩余空间.您还可以在编译并安装完毕glibc库之后再执行一次看看这玩意儿到底 得占多大地儿。
cd ..
mkdir glibc-build
../glibc-2.1.3/configure --enable-add-ons --prefix=/usr
make
make install_root=/mnt/target install
注意了,我们还有别的方法来告知一个软件包该装到什么地方。
7. SysVinit初始化脚本包
编译并安装SysVinit可执行代码是非常之简洁明了的.我偷懒一次,就给您操作命令吧.假定您已经解压并且进入SysVinit源码目录了∶
cd src
make
ROOT=/mnt/target make install
另外还有很多与init相关的脚本.在SysVinit包里面有一些工作正常的范例脚本,但是您得自个儿手工安装了.它们在SysVinit源码树中是有 层次地布置在debian/etc下面的.您只需要执行类似这样的命令∶cd ../debian/etc; cp -r * /mnt/target/etc 直接把它们复制到目标系统的etc目录下面就行了.当然了,您最好是在复制之前查看一下.
当重启之后,目标系统的内核就会加载init,一切都该各就其位了.此时的问题可能是脚本不能正常运行,因为没有命令解释器bash来解释执行这些脚本. 而且init还会尝试执行getty,但是根本就没有getty可供运行.请重新启动并确认没有其它的错误。
8. Ncurses库
我们所需要的下一个东东是命令解释器Bash,而bash需要ncurses库,所以我们得先安装这玩意儿.ncurses库可以代替termcap处理 文本屏幕的活计,同时还通过支持termcap调用提供了向后兼容性.为了拥有一个简洁新潮的系统,我觉得最好是禁止旧式的termcap方法.如果您后 头要编译使用了termcap的较老的应用程序,您可能会不断地与麻烦为伴了.但是您至少会知道什么东东使用了什么东东.如果您必须要用,那么您可以重新 编译ncurses库,使其带有termcap支持.
我所使用的命令是∶
./configure --prefix=/usr --with-install-prefix=/mnt/target \
--with-shared --disable-termcap
make
make install
9. Bash命令解释器
为了把bash安装到我认为它该呆的地方,我花费了很多时间做了大量阅读和思考以及不断地尝试和出错,可谓是历尽千辛万苦啊.我所使用的配置选项是∶
./configure --prefix=/mnt/target/usr/local \
--exec-prefix=/mnt/target --with-curses
一旦您已经编译并安装了bash之后,您需要生成一个符号连接,就象这样∶
cd /mnt/target/bin; ln -s bash sh.
这是因为脚本通常头一句是这么写着的∶
#!/bin/sh
如果您没有这么一个符号连接,那么您的脚本就不能运行,因为它们会去寻找/bin/sh而非/bin/bash.
如果您愿意,您也可以到这里时重新启动一次.您会注意到脚本这一次确实运行了.虽然您还是没能登录(login),这是因为还没有安装getty或者login 这些程序。
10. Util-linux (getty 和login)
软件包util-linux包含有agetty和login.我们需要这两个程序才能登录系统(log in)和得到命令行提示符(bash prompt).在安装之后,请在目标系统的/sbin目录下为agetty建立一个符号连接到getty.getty是所有Unix类系统当中被认为应 该呆在那个地方的程序之一,所以生成连接的主意要强于改动inittab来运行agetty.
对于util-linux这个包,我剩下的一个问题就是该包的编译.这个包还包含有more这个程序,而我没法让make进程给more在目标系统上做一 个指向ncurses 5库的连接,而不是在源头系统上指向ncurses 4库的连接.我会努力克服这个困难的。
您还得在目标系统上准备一个密码文件/etc/passwd.login登录程序正是通过查询该文件来确认您是否允许登录的.因为此次我们只是打造一个玩 具系统,所以我们可以只设置根系统用户就够了,而且不需要任何密码!! 只需要在目标系统的密码文件/etc/passwd加上如下一行即可∶
root::0:0:root:/root:/bin/bash
所有的域是通过冒号(:)分隔开的,自左向右分别代表∶用户名称(user id),密码密串(password),用户号码(user number),用户群组号码(group number),用户真实姓名(user"s name),用户主目录(home directory)和缺省命令解释器(default shell)。
11. Sh-utils
我们所必须的最后一个软件包就是GNU sh-utils包.我们此时所需要从这个包里面得到的唯一的程序就是stty,它会在/etc/init.d/rc里面用到.而后者是用于改变运行级别 和进入初始化运行级别的脚本.实际上我有一个而且用过仅包含有stty的软件包,但是却忘了是从何处得到的了.使用GNU的软件包是个好主意,因为在里头 还有其它您需要的东西,增加了这些东东会使得系统可用性更好。
好了,打造完毕.您现在应该拥有一个可以启动并且能够提示您登录的系统了.输入``root"",您就会进入命令解释器了.但是您做不了很多事情,甚至没 有一个ls命令给您看看您的作品里面都有些什么东西.请连续按两次TAB键,您就会看到可用的命令了.这大概是这个系统中,我所发现的最令我满意的事情。
12. 可用性商榷
看起来好像我们打造的是一个毫无用处的系统.说真的,要让它能够有实用价值也并不是什么难事.首先要做的事情之一就是您应该使得根文件系统(root filesystem)以可读写方式挂载起来.SysVinit软件包里面有干这活儿的脚本,就在/etc/init.d/mountall.sh里面. 还执行了一次mount -a把所有在/etc/fstab当中的条目以您所指定的方式挂载起来.请在目标系统的etc/rc2.d目录下生成一个类似S05mountall的符 号连接。
您可能会看到这个脚本会用到您尚未安装的命令.如果真是这样,找到包含该命令的软件包并安装之.请参看 随机小技巧(Random Tips)这一小节,了解如何查找软件包.
看看在/etc/init.d里面的其它脚本.它们大部分都应该包含在任何正经的系统里面.一次添加一个,别忘了要确定添加下一个之前个个都运行无误.请 对照文件层次结构标准(File Heirarchy Standard),请参看 文件系统(Filesystem)一节.那里有一个命令列表,都是该在/bin和/sbin的命令.请确定您已经把那里列举的所有命令都安装在系统上了. 最好就是再找找相关这类问题的POSIX文档来看看.
从此,在这个系统里面添加更多必要的软件包就真是个事儿了.越是早些把编译工具,比如说gcc和make这些添加进去就越好.一旦这些都完工了,您就可以利用目标系统来自我生息,就会越来越简单了.
13. 更多信息
13.1 随机小技巧
如果您的Linux系统上曾经使用RPM安装过有一个叫做thingy命令,而您想获知这个命令的源码来源,那么您就使用如下命令∶
rpm -qif `which thingy`
如果您有小红帽RedHat的源码光盘,那么您就可以使用下列命令安装源码包了∶
rpm -i /mnt/cdrom/SRPMS/what.it.just.said-1.2.srpm
这个命令会把tar包以及任何RedHat补丁包放到/usr/src/redhat/SOURCES目录下面。
13.2 资源链接
* 有一个关于从源代码编译软件的小型实作指南(mini-howto),就是《软件打造小小实作指南(Software Building mini-HOWTO)》:
.
*
另外还有一个关于从一穷二白空手起家打造一个Linux系统的实作指南.该文更为集中于打造一个有实际应用价值的系统,而不仅仅是一个实习.请看∶
《Linux系统空手道实作指南篇(The Linux From Scratch HOWTO)》: .
* Unix文件系统标准(Unix File System Standard) 还有一个关于Unix文件系统标准的
链接.这个标准描述了在一个Unix系统中什么东东该呆在什么位置以及原因.它还描述了在/bin,/sbin等等目录中最小化的要求.如果您的目标是要
打造一个小而全的系统,那么这个标准正是一个好的参考.
14. Administrivia
14.1 版权声明(Copyright)
本文版权所有,归属Greg O"Keefe.欢迎您在遵循 GNU通用公共许可证(GNU General Public Licence)的各项条款的前提下无需付费来使用,复制,散发或者修改本文. 如果您在其它文档里面使用了本文的全文或者部分,请在鸣谢录提提我就行了.
This document is copyright (c) 1999, 2000 Greg O"Keefe. You are welcome to use, copy, distribute or modify it, without charge, under the terms of the GNU GPL (GNU General Public Licence). Please acknowledge me if you use all or part of this in another document.
14.2 主页
本文最新的英文版本"From Powerup To Bash Prompt"可在此找到∶
14.3 您的反馈意见
我很乐意从读者您那儿得知任何评论、改进意见和建议.请写信给我∶ Greg O"Keefe
14.4 鸣谢录
本文所提及的产品名称是相应持有者的商标,在此我一并致谢. 我想对以下人员致谢,因为他们的帮助才有了这篇实作指南.
Michael Emery
因其提醒我注意到Unios.
Tim Little
因其提供了关于/etc/passwd的一些线索.
sPaKr on #linux in efnet
因其发现syslogd需要/etc/services的支持以及介绍给我 使用短语``rolling your own""来表述从源码打造系统.
Alex Aitkin
因其引起了我对Vico以及他的``verum ipsum factum""(对编译进一步的理解) 的注意.
Dennis Scott
因其纠正了我的十六进制计算错误.
jdd
因其指出一些拼写错误.
14.5 修订历史记录
0.8
* 最初版本.自"From PowerUp to Bash Prompt(从加电启动到Bash提示符)实作篇"分离独立出来.
14.6 未来计划(TODO)
* 转换为docbook格式