Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统 nsswitch.conf配置文件

时间:2022-09-05 19:39:11

Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统  nsswitch.conf配置文件

朋友们,今天我对你们说,在此时此刻,我们虽然遭受种种困难和挫折,我仍然有一个梦想。
……
我梦想有一天,这个国家会站起来,并真正实现其信条的真谛:‘我们认为这些真理是不言而喻的:人人生而平等。’
……
我梦想有一天,幽谷上升、高山下降,坎坷曲折之路成坦途,圣光披露、照满人间。
——马丁·路德·金
这有点扯远了,我肯定是比不上马丁·路德·金的。不过我曾经也有一个梦想,就是:当我的电脑一开机时,五星红旗迎风飘扬,闪闪的红星放光芒。虽然你马上就能想到:修改一下开机画面就行了。不过我的梦想是有一天我可以开发出自己的操作系统,而且这个梦想伴随了我十多年。直到我养家、娶妻、生子,才慢慢地开始忘却……因为生活太TM不容易了……
经过这么多年工作上的磕磕绊绊与不断地学习,越发地觉得自己的能力与梦想越来越远也是最终放弃它的主要原因。这或许就是知道的越多,不知道的也越多罢。不过在追逐梦想的同时,也逐渐解开了我曾经的不少疑惑。
编译器能够将源代码转化为可以运行的程序,可是编译器也是程序,编译器怎么来的?程序需要运行在操作系统之上,编译器也是程序,操作系统又是靠编译器编译出来的,到底谁先谁后啊?一个操作系统需要具备哪些素质才能运行程序,编译程序?我想你也可能会有这个疑问!这基本上算是计算机世界的“鸡”和“蛋”的问题,只不过在这个世界里这个问题有答案。
这一章里我们将要从头编译一套Linux系统,顺便一一为你解答这些问题。这一章大体上会分为三个部分。可以将我们要编译的Linux比作一个“婴儿”。第一部分是准备环境,也就是为我们即将出生的“婴儿”准备一个功能齐备的产房;第二部分讲述作为一个可以独立运行的Linux系统所必须具备的基本元素,为我们刚刚出生的“婴儿”准备一张温暖的床;第三部分着重讲解Linux内核的配置和编译过程,为我们即将出生的“婴儿”塑造一颗与众不同的心房。
本章的内容源自LFS,但是高于LFS,因为我们讲述了LFS所没有告诉你的东西,而这些正是你所疑惑的。LFS是Linux From Scratch的缩写,翻译过来就是Linux从零开始。它是一个Linux发行版,但是很特别,实际上只是一本电子书,告诉你如何从头到尾编译一个Linux系统。
好了,我们开始吧!

16.1初识工具链——准备环境的必备工具
等等,在正式开始之前,我还要让你了解一个重要的知识,那就是工具链。工具链是我们用来准备环境的一个必备工具。它是编译器、连接器、程序库和一些其他辅助工具的集合。为接下来打造编译Linux的环境提供工具上的支持。正所谓“工欲善其事必先利其器”之所在。我们需要的工具链,可以说得上是编译器、连接器、程序库和Linux内核的四角恋爱故事,故事的内容自然是曲折而又精彩。那么就且听我细细道来罢。

16.1.1 编译器
编译器这个东东其实不用多解释的,就是将源代码翻译成对应的机器代码的工具。但是,编译器直接输出的代码是不能直接执行的,因为即没有安排好执行顺序也没有指定从哪里开始。正是因为这样,编译器输出的文件一般被称为目标文件。
Linux上使用的名为gcc的编译器集合,全称是GNU Compiler Collection。它包含了C、C++、Objective-C、Fortran、Java、Ada等语言。同时也提供了一些程序库,如:libstdc++、libgcj,……。gcc还是一个开放框架,人们可以非常容易地利用gcc实现自己设计的编程语言,并且使他们设计的语言成为一个编译型语言。
gcc的C编译器是Linux的标准编译器。Linux内核完全依赖于gcc,其他编译器不能编译Linux内核。另外,由于ABI(Application Binary Interface)的不兼容,其他编译器也不适合Linux上的大多数软件的编译,尤其那些使用C++作为开发语言的软件系统。目前IntelC/C++编译器开始兼容gcc的ABI,因此现在可以采用Intel C/C++编译器编译Linux上的软件,但是内核不行。

16.1.2 连接器
刚才说过,编译器生成的机器代码是不能执行的,因为没有安排好执行顺序也不知道从哪儿开始。这需要连接器来帮忙。连接器负责将编译器生成的机器代码进行排序并告诉计算机(严格来讲是操作系统)从什么地方开始执行。同时连接器还要负责一些其他事情,比如程序需要向屏幕输出一些内容,那么如何操作也是由连接器告诉程序的。
Linux中并没有提供单独的连接器。不过GNU组织提供了一个名为binutils的工具包,它包含了一个名为ld的连接器,Linux使用的就是它。
从binutils这个工具包的名字上看,应该是一个二进制工具包,实际上也是这样。它包含了汇编器、反汇编器、elf可执行文件分析器等重要工具。Linux内核中那很少量的汇编代码就需要这个工具包提供的汇编器进行汇编。因此这是我们必备的工具。

16.1.3 程序库  glibc->gnu c library
程序库其实也不用多解释的,因为我们都很“懒”,所以我们在写程序的时候都喜欢找拥有各种功能的程序库来满足需要。因为好多有用的算法和功能别人都实现了,我们是没有必要重新造*的。作为C语言的程序员,最经常摆弄的程序库其实是两个。一是C标准库,二是操作系统的API。
Linux操作系统很霸气,它将C标准库和操作系统API通过一个名为glibc的程序库一同提供了。因此很多时候Linux上的程序员是分不清哪些函数是C标准库,哪些是系统API的。
前面说过,连接器可以告诉程序如何向屏幕输出内容,这是它知道glibc程序库提供了这个功能,让程序调用glibc提供的相关功能实现的。
既然glibc提供了API,那么也就意味着Linux上的所有程序都要依赖glibc,这包括我前面提到的gcc和binutils了。而且既然是API就一定与Linux的内核有依赖关系。
还要说一句的是,Linux系统中glibc不是唯一选择。在嵌入式Linux中好多时候使用的是uClibc。如果你足够强大,也可以自己提供类似的东西,以决定提供哪些功能给用户,或者简化哪些功能的实现。这或许就是Linux最引人入胜的地方了,因为一切都可以随你所愿。

http://www.cnblogs.com/MYSQLZOUQI/p/5257200.html

glibc库是什么?没有glibc库,就没有Linux。我们平时用过的malloc和strcpy等函数
都是glibc这位仁兄提供的。除此之外,它还提供了网络编程中要用到的Socket API接口。之前曝光的glibc库漏洞

glibc->gnu c library

Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统  nsswitch.conf配置文件

glibc版本

rpm -qa |grep glibc
glibc-2.12-1.166.el6_7.3.x86_64
glibc-headers-2.12-1.166.el6_7.3.x86_64
glibc-2.12-1.166.el6_7.3.i686
glibc-devel-2.12-1.166.el6_7.3.x86_64
glibc-common-2.12-1.166.el6_7.3.x86_64

16.1.4 工具链——破解奇特的四角恋
到了这里,四角恋的三个主角已经一一登场了。第四个就是Linux内核了。这个不多解释,因为自知能力有限,这一辈子我都解释不完。其实Linus本人现在都无法诠释Linux,这跟你的父母现在无法诠释你的一切是一样的道理。
这个四角恋的关系是这样的:glibc需要Linux内核来决定提供什么样的功能;gcc和binutils需要glibc来提供基本的功能实现,这样也就将它们绑定在具体的Linux内核之上;Linux内核需要gcc和binutils来完成编译和连接使得自己能够运行;glibc需要gcc和binutils将源代码变成可供别人乃至gcc和binutils使用。这个显然有点乱,我们看一下它们的关系图,见

图16.1:

Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统  nsswitch.conf配置文件

从图16.1中可以明显地看出,除glibc与Linux内核(Linux内核自己实现一切功能)之间是单向依赖之外,其他的都是双向依赖。这显然就是一个死结。若要从头到尾编译Linux就必须先解开这个死结,并且最后还要重新构成这个死结。如何做到呢?使用工具链技术。
首先我们要清楚一件事情,就现在所能得到的所有工具,要编译一个操作系统,是在另外一个操作系统之上完成的。这个“另外一个操作系统”通常也被称之为HOST系统,或宿主系统。被编译的操作系统通常被称为TARGET系统,或目标系统。其实任何流行的操作系统都可以作为宿主系统,这章内容的宿主系统是CentOS 6.4。当然你也可以选择其他系统,甚至Windows也可以(稍微有点难度)。另外,在64位时代我选择编译一个64位的Linux,为了简单起见我选择了64位的宿主系统,而且也没有考虑要兼容32位系统。让32位系统一边玩去吧!
工具链就是从宿主系统中解开四角恋并在目标系统中形成新的四角恋的中间工具。它提供gcc、glibc、binutils的完美替身去欺骗Linux内核,从而完成这个过程的转换。
工具链其实是一种被称为“交叉编译”的技术,它不但在相同架构的机器上完成这种“四角恋”的迁移,还可以在不同架构的机器之间做这种转换。因此掌握好工具链技术也是我们所有程序员的必修课程。

16.2 准备环境
好了,我想我应该解释清楚了一些基础概念。那么接下来开始正式进入准备环境的阶段。这里我先做一些假设。假设你已经完全熟练了Linux系统的操作;假设你对C语言有一些了解;假设你是Linux最忠实的粉丝……。
这也是最初始的阶段,去打造一个工具链。这就相当于为我们即将出生的Linux打造一个功能齐备的产房。在任何情况下都能够保证它的顺利出生。
这一阶段也是非常重要的阶段。在这个阶段所发生的错误都会严重影响到我们即将要编译的新的Linux系统,甚至会导致我们无法完成这一目标。所以需要非常谨慎,确保每一个环节都准确无误。

16.2.1 宿主系统环境
不管怎么样,宿主系统的环境我们还是要设定一下的。主要是为了方便我们后面的操作。
首先是要准备一个独立的磁盘分区,一般2G左右就够了。如果你觉得有点麻烦,那么有2G以上的*空间也行。为新的Linux划分点交换空间也是必然的,多大就看你的个人喜好。我现在假设你划分了一个独立的分区。那么首先就要挂接,挂接点是什么地方,自己决定就行。我挂接到了/mnt/m13目录下。
然后在新的分区上创建两个目录,分别是toolchain和sources,分别用于工具链和存放源代码。源代码列表我就不列举了,因为接下来你都会看到。至于你选择什么时候下载这些源代码,随你个人喜好。我也不能保证我所使用的软件包都是最新的,其实最新的也许是不稳定的。
之后就是在你的宿主环境的根目录下创建一个到toolchain目录下的符号连接。至于为什么这么做,其实就是为了方便。如果你不嫌麻烦,完全可以忽略这个步骤。但是我强烈建议要这么做,因为之后会真的很麻烦。我使用的命令是:

# In-sv/mnt/m13/toolchain/toolchain

此外,我是一向不主张直接使用root账号的,所以还要添加一个独立的用户用来编译这个新生的Linux系统。这里最重要的一个原因就是不会因为某一个误操作破坏了宿主系统。将toolchain和sources目录的拥有者更改为你新添加的用户,否则你也无法更动这个目录的内容,这显然不是你想要的。当添加完新的用户就切换到新用户环境下。一定记得这么做,因为下面的操作必须是针对这个新用户环境的。
由于我们要编译一个64位版本的Linux,那么还需要在/toolchain目录中创建一个lib64子目录,同时在/toolchain/下建立一个名为lib的到它的符号链接。这个设定很重要,就是为了“欺骗”。这是一种善意的欺骗,如果你是一个一直都是说实话的人,我保证你找不到一个你喜欢的好姑娘;)
修改环境变量PATH,操作是这样的:

$ export PATH=/toolchain/bin:$PATH

PATH环境变量指定了shell命令的默认搜索路径。这样设定就是当我们工具链中的工具生成之后,默认执行的是它们,而不是宿主系统自带的。这也是解除四角恋的开始。
宿主系统环境的准备就这么多了,是不是简单得出乎你的意料了?没关系,接下来就没那么简单了。

16.2.2 生成工具链的binutils
应该最先生成的是binutils。因为在生成gcc和glibc时,它们会检测连接器和汇编器的特性来决定自己是否需要开启某些特性。需要执行的所有命令如下:

$ tar vxf binutils-2.22.tar.bz2
$ mkdir binutils-build
$ cd binutils-build
$ ../binutils-2.22/configure\
--prefix=/toolchain--disable-nls--disable-werror\
--target=x86_64-mgc3-linux-gnu
$ make-j
$ make install

整个过程不是很难理解。你或许会问新建一个binutils-build目录来做神马?这是官方文档说这样做的,至少遵循官方建议的方式不会出现什么错误,所以照做就可以了。至于执行configure的命令时一些命令参数的含义我解释一下:
--prefix=/toolchain
其实这个参数我们在前面的章节中是介绍过的,就是要告诉configure脚本,把binutils软件包中的程序安装到/toolchina目录中,也就是/mnt/m13/toolchain。
--disable-nls
这个参数禁止了国际化(通常简称il8n)。此时根本不需要国际化支持。
--disable-werror
这个参数可以防止由于你的系统提供的gcc在产生警告事件时停止创建过程。
--target=x86_64-mgc3-linux-gnu
这个参数用来声明目标系统的名称,x86_64-mgc3-linux-gnu是MagicLinux3.0系统的名称。同时这也是进行交叉编译时的重要概念。当指定这个参数时,安装的程序会带有x86_64-mgc3-linux-gnu的前缀,这样就可以与宿主系统的程序进行区分。
我在执行make的时候,带有一个-j选项。这个选项本书在前面的章节也是讲过的,这里复述一次。这个选项是告诉make采用多任务方式并行生成目标。现在已经是多核时代了,所以这个命令选项大家还是常用为好,可以极大地缩短编译Linux这种大项目的时间。另外,make的多任务模式比较吃内存,所以内存小的可以考虑在-j后面添加一个数字来表明最多启动多少个任务。

16.2.3 生成工具链的gcc
连接器现在准备好了,而且我们不能马上使用它,因为我们还没有自己的glibc。也正因为如此等我们生成glibc之后还要再次生成gcc,我们之前生成binutils也要这样处理,因为现在还无法与宿主系统完全脱离开来。
需要执行的所有命令如下:

$ tar jvxf gcc-4.6..tar.bz2
$ cd gcc-4.6.
$ tar jvxf../mpfr-3.1..tar.bz2
$ mv-v mpfr-3.1. mpfr
$ tar jvxf../gmp-5.0..tar.bz2
$ mv -v gmp-5.0. gmp
$ tar zvxf../mpc- ..tar.gz
$ mv-v mpc-0.9 mpc
$ cd..
$ mkdir gcc-build
$ cd gcc-build
$ ../gcc-4.6./configure --prefix=/toolchain\
--target=x86_64-mgc3-linux-gnu—disable-nls\
--disable-shared --disable-multilib-disable-decimal-float\
--Disable-threads—disable-libmudflap—disable-libssp\
--disable-libgomp—disable-libquadmath\
--disable-target-libiberty—disable-target-zlib\
--enable-languages=c --without-ppl –without-cloog\
--with-mpfr-include=$(pwd)/../gcc-4.6./mpfr/src\
--with-mpfr-lib=$(pwd)/mpfr/src/.libs
$ make-j
$ make install

需要敲入这么多命令,真够唬人的,其实很简单。
首先,当今的gcc必须依赖mpfr、gmp和mpc这三个高精度数学运算库,所以最开始的命令是将这些库的源代码放入gcc的源代码的路径下。
接下来就是对源代码的配置和make过程了。我解释一下configure程序所使用的一些特殊参数:
--target=x86_64-mgc3-linux-gnu
还记得在生成binutils时用的这个参数吗?当给定这个参数时configure程序先会去查找所有可用的以x86_64-mgc3-linux-gnu作为文件名前缀的程序,用于确保新生成的gcc能够与它们配合使用。它会找到我们之前生成的连接器和汇编器等工具,gcc在编译别的软件时是要调用它们完成一些汇编和连接过程的。为什么能够找到呢?别忘了我们之前是设定过$PATH这个环境变量的。如果你之前忘记设定了,那么这个时候所生成的gcc就会有错。
--disable-……—withou-……
这些参数都是为了关闭gcc的一些特性,因为对于现在这个gcc是不需要的,这样也能节省很多时间。
--enable-languages=c
这个参数是说只编译C编译器,因为现在只需要C编译器。
--with-mpfr-include=$(pwd)/../gcc-4.6.2/mpfr/src
这个参数说明mpfr的头文件搜索路径,默认情况下会搜索宿主系统的的头文件路径,这是不希望的。尤其是宿主系统没有提供mpfr时,就会报错。
--with-mpfr-lib=$(pwd)/mpfr/src/.libs
这个参数说明在连接gcc的C编译器时,mpfr的库文件位置,否则会选择宿主的mpfr库。
最后就是make和安装了,不用多解释。但是要注意,还需要做一些收尾工作。干什么?骗人。骗谁呢?接下来要生成的glibc。骗它什么呢?骗它我们有libgcc_eh.a这个文件。因为缺少这个文件,生成glibc的时候会报错,glibc需要它。但是我们在生成gcc时,使用--disable-shared参数,这会导致无法生成libgcc_eh.a这个文件。怎么骗呢?做个符号连接到libgcc.a文件。它们功能差不多,下一步生成的glibc用它提供的功能就足够了。
libgcc.a的文件路径可以通过这样的命令获得:
$ x86_64-mgc3-linux-gnu-gcc—print-libgcc-file-name
如果你之前的操作没有什么错误,它一定在你的工具链路径下。

16.2.4 生成工具链的glibc
前面说过glibc就是标准C库和API,所以它是不会依赖什么程序库了,也正因为这样,我们现在可以用刚刚生成的gcc来编译它。不过glibc对Linux内核还是有依赖。glibc与Linux内核的依赖其实是很微妙的,它并不依赖于内核的任何二进制代码。因为glibc与内核的沟通是通过系统调用实现的,所以glibc需要知道内核都提供了哪些系统调用。这就要求将内核的一些头文件指定给它。顺便说一句,同一系列的内核在系统调用上不会有太大变化,比如2.6系列和如今的3.0系列。我们首先就给glibc提供内核的头文件,所需执行的操作如下:

$ tar jvxf linux-3.1..tar.bz2
$ cd linux-3.1.
$ make mroroper
$ make headers_check
$ make INSTALL_HDR_PATH=dest headers_install
$ cp-rv dest/include/*/toolchain/include/

这些命令最终将Linux内核提供的系统头文件复制到工具链的include目录下。
先要补充说明一下,当前的glibc不再支持i386体系了,因此它的开发者建议在生成glibc时,最好使用-march=i486这个编译选项。但是要是说,上个世纪的东西该扔就扔了吧,直接使用-march=i686,至少我认为有收藏古董爱好的还是极少数人。不过这些选项在64位时代已经不合适了,所以我不过多介绍它了。如果你一定要抱着32位系统不放,那你自己研究吧:)
生成glibc需要下面这些命令:

$ tar vxf glibc-2.14..tar.bz2
$ mkdir glibc-build
$ cd glibc-build
$ ../glibc-2.14./configure--prefix=/toolchain\
--host=x86_64-mgc3-linux-gnu\
--build=$(../glibc-2.14./scripts/config.guess)\
--disable-profile—enable-add-ons—enable-kernel=2.6
--with-headers=/toolchain/include\
libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes
$ make-j
$ make install
rpm  -qa|grep glibc  2.12

就我所使用的这个glibc版本,当执行到configure程序的时候一定会报告一个错误。说它找不到“cpuid.h”这个头文件。因为我们刚才生成的gcc并不包含这个文件。但是glibc说不行,没有它我不干活。这怎么办?让它闭嘴。因为这个时候我们根本不需要这个功能。所以让它闭嘴是最好的办法。怎么让他闭嘴呢?有人说骗它,弄个“cpuid.h”文件骗它。学得还真快,不过我们之前已经骗过它一次了(还记得libgcc_eh.a的事情吗?)。要我说,同样的方法不能用两次,因为第二次不一定灵,所以最好是用其他手段。我的手段是给它吃“迷幻药”,这个够恶毒吧,千万别说我卑鄙,因为我也很无奈。
“迷幻药”是这么下的。在glibc源代码路径下的sysdeps/i386/子路径下也有一个configure程序。它就是报错的源头。细心的你会发现,我一直在说i386过时了,为什么又跟i386扯上关系了?原因是代码复用,64位系统也是用这段代码。用你习惯的编辑器打开这个configure文件,跳转到第635行(也可能是别的地方,我下载的代码是在这里),你会看到这样的代码:
ac_fn_c_check_header-mongrel“$LINENO”“cpuid.h”\
“ac_cv_header_cpuid_h”“$ac_includes default”
把它改成这个样子:
ac_fn_c_check_header_compile“$LINENO”“cpuid.h”“ac_cv_header_cpuid_h”
就行了。之后再执行我们上面的configure程序就不会再报错了。
configure程序各选项的含义如下:
--host=x86_64-mgc3-linux-gnu
这个参数跟我们之前见到的--target正好是相反的,它说明了宿主系统是谁。你可能会问,宿主系统不就是我在使用的吗?为什么还要指定呢?这就是关键所在了。如果不指定新的宿主系统,则现在就会使用当前宿主系统的编译器和连接器生成glibc,那等于我们之前所作的工作都白费。指定了这个参数后,就会使用我们刚刚生成的gcc和binutils了。这是典型的交叉编译方法。
--build=$(../glibc-2.14.1/scripts/config.guess)
这个参数用于指定软件的系统平台,当前对于工具链来讲还谈不上什么平台,就调用config.guess来进行猜测。
--disable-profile
忽略掉profiling信息相关的库文件,我们这个时候是不需要的。
--enable-add-ons
这个是告诉glibc使用附加的NPTL(本地POSIX线程库)包作为线程库。
--enable-kernel=2.6
告诉glibc只支持2.6以上的内核,虽然我们选择了3.1.6的内核,但是为了让接下来所生成的程序能够在宿主系统中运行,还是需要使用较低的内核版本。
--with-headers=/toolchain/include
告诉glibc所使用的系统头文件路径。
libc_cv_forced_unwind=yes和libc_c_c_cleanup=yes
其实说到这里我有点不好意思了。为什么?这又是一次欺骗。需要警告大家的是,不会一点善意的“欺骗”可能得不到女人的芳心,但是总是欺骗会得到女人的伤心。所以可以这样对待glibc,但是一定不要这样对待你的女人。为什么还要欺骗glibc呢?因为它的configure程序默认会进行forcede_unwind和c_cleanup的功能测试。而进行这两项测试需要用到连接器的功能。但是我们刚刚生成的连接器,由于还没有glibc是不能正常工作的,所以执行这两项测试就一定会报错使得无法继续。那没办法,谁让glibc这么事儿妈呢?这也警告一些事儿妈的女人,太事儿妈了是会被骗滴:)
16.2.5 解决工具链的一些问题
看来这个时候编译器、连接器、程序库都已经搞定了,是不是接下来就能开始编译我们的目标系统了呢?不行!目前的这个工具链还不能真正工作起来。不信我们就做一个实验试试。编写一个简单的C代码,我用下面这些命令:

$ echo“main(){}”>ttt.c
$ x86_64-mgc3-linux-gnu-gcc-B/toolchain/lib64 ttt.c
$ readelf-l a.out

看看结果,是不是有一行类似下面的内容:
[Requesting program interpreter:/lib64/ld-linux-x86-64.so.2]
这是不对的。readelf是分析elf可执行文件格式的工具,“-1”选项是用来显示可执行文件各段头内容的,通过它可以了解一个可执行文件的依赖关系。上面的结果表明新的编译器产生的可执行文件还是依赖于宿主系统的ld-linux-x86-64.so.2。这是glibc的一部分,换句话说刚才生成的glib。根本不会被使用。另外还有一个问题就是当我使用x86_64-mgc3-linux-gnu-gcc来编译“ttt.c”的时候必须指定参数“-B/toolchain/lib64”,告诉它C运行时库在哪里,否则就会报告找不到“crtl.o”等文件。这也是不行的。
第一个问题现在就需要解决。方法是通过gcc的specs文件。这个文件本来是没有的,但是只要存在,gcc就会按照它的指示办事。这个文件怎么写呢?不用写。gcc可以帮你生成。通过命令:
# x86_64-mgc3-linux-gnu-gcc-dumpsecs>specs
就可以生成。不过现在这个文件的作用跟gcc的默认行为没啥区别,所以要在它的基础之上修改。修改有两个地方。第一个地方是将类似:
*cPP:
%{posix:-D_POSIX_SOURCE}%{pthread:-D_REENTRANT}
这样的内容修改成这个样子:
*cpp:
%{posix:-D_POSIX_SOURCE}%{pthread:-D_REENTRANT-isystem
/toolchain/include
这告诉gcc的默认头文件搜索路径是/toolchain/include。第二是将所有类似:
/lib/ld-linux.so.2和/lib64/ld-linux-x86-64.so.2
修改成:
/toolchain/lib/ld-linux.so.2和/toolchain/lib64/ld-linux-x86-64.so.2
这告诉gcc要使用工具链的glibc。
修改好了之后,需要将specs文件复制到与libgcc.a文件相同的路径(还记得前面说的获取这个路径的方法吗?)。之后执行一下最开始的测试。如果修改得没有错误,现在得到的结果应该类似这样的:
[Requesting program interpreter:/toolchain/lib64/ld-linux-x86-64.so.2]
如果结果有出入,那么就检查一下specs文件是否修改正确了。或者更前面的操作有错误。如果是前面的操作有错误,那就会很悲催,从新再来一次吧!
第二个问题怎么解决呢?不是很好解决,只能重新生成binutils和gcc了。为什么不在第一次生成binutils时就解决这个问题呢?因为那个时候还没有glibc,所以那个时候没法解决。另外。因为解决了第一个问题,我们第二次在生成binutils和gcc时就可以使用工具链的环境了,这使得我们新生成的binutils和gcc与宿主系统没什么关系了。

16.2.6 第二次生成工具链的binutils
第二次生成工具链的binutils与第一次会有本质区别。第一次使用了宿主系统的编译器和连接器,这次要使用我们自己的了。因此相关的编译参数会有很大不同。使用如下命令:

$ CC=“x86_64-mgc3-linux-gnu-gcc-B/toolchain/lib64”\
AR=x86_64-mgc3-linux-gnu-ar RANLIB=x86_64-mgc3-linux-gnu-ranlib\
../binutils-2.22/configure--prefix=/toolchain--disable-nls\
--with-lib-path=/toolchain/lib64
$ make-j
$ make install

这次没有指定--target参数,因为我们选择的编译器和连接器与目标系统是一致的,所以不用考虑交叉编译问题。其他新增参数含义如下:
CC=“x86_64-mgc3-linux-gnu-gcc-B/toolchain/lib64”
这修改了Makefile的$(CC)变量,也就是指定了编译器是我们工具链的。接下来的“AR”和“RANLIB”的作用是相同的,不多解释了。
--with-lib-path=/toolchain/lib64
这个就解决了前面所说的“第二个”问题。告诉连接器程序库的搜索路径是什么地方。
虽然我们安装完了新的binutils了,而且也与宿主系统没有半毛钱关系了,但是我们还得做一些有意义的工作。是什么呢?看下面要执行的命令:

$ make-C ld clean
$ make-C ld LIB_PATH=/usr/lib64:/lib64
$ cp-v ld/ld-new/toolchain/bin

这些命令的意思是这样的。首先将开始生成的ld程序清除掉。然后使用新的编译选项从新编译。这个新的编译选项LIB_PATH可以指定ld程序,也就是连接器的程序库默认搜索路径。这会导致一个名为ld-new的程序被编译出来(binutils的开发者想得很周到:)。最后复制到/toolchain/bin路径下,以备后面的过程所使用。

16.2.7 第二次生成工具链的gcc
第二次生成工具链的gcc有点复杂。因为这次生成的gcc是要独立于任何系统的,首先就得让它规矩一点,不要再与谁勾勾搭搭了。要做到这一点可以想像一下我们聪明的祖先们是怎么对付太监的。对,净身!我们先要给gcc净身。怎么净,净什么呢?当然是惹祸的根——fixincludes脚本。在gcc的编译过程会运行fixincludes脚本来扫描系统头文件目录,并找出需要修正的头文件,然后把修正后的头文件放到gcc专属头文件目录里。由于gcc专属头文件会被优先搜索,结果就是gcc使用的头文件是宿主系统的头文件。这是一种好心办坏事的行为,虽然它并不是一定“惹是生非”(或许找不到需要修正的头文件),但还是把它除掉最为安全。通过修改gcc/Makefile.in文件来完成这个操作。将“./fixinc.sh”用“-c true”进行替换(只有一处是这么写的)。
然而gcc“惹是生非”的还不止一处(很坚强啊:)。我们都知道,作为C语言的程序都是以main()函数作为程序的入口的。但是我们已经知道,编译器并没有指定一个程序应该从那里执行,这是由连接器确定的。连接器怎么就知道C语言的程序是从main()开始的呢?原来C编译器要负责提供一些“启动文件”,这些文件会告诉连接器程序的入口是main()函数,而不是end()函数。早期版本的gcc会默认根据--prefix参数中指定的路径开始搜索“启动文件”。但是从gcc4.3开始,就不再提供这个特性了。所以这个祸根必须剔除。怎么剔除呢?还有点麻烦,需要修改gcc的源代码。不过不用紧张,代码量很少。只要修改gcc/gcc.c文件就行了。对于4.6.2版的gcc,从第6385行开始,会看到这样的代码:

else if(*cross_compile ==‘’)
{
add-prefix(&startfile-prefixes,
concat (gcc_exec_prefix
?gcc_exec-prefix:standard-exec_prefix,
machine_suffix,
standard_startfile_prefix,NULL),
NULL,PREFIX_PRIORITY_LAST,,);
}

把它改成这样:

else if(*cross_compile==‘’)
{
add_prefix(&startfile_prefixes,
concat (gcc_exec_prefix
?gcc_exec_prefix:standard-exec_prefix,
machine_suffix,
standard_startfile_prefix,NULL),
NULL,PREFIX_PRIORITY_LAST,,);
Add_prefix(&startfile_prefixes,
concat (standard_exec_prefix,
machine_suffix,
standard_startfile_prefix,NULL),
NULL,PREFIX_PRIORITY_LAST,,);
}

就可以了。
不过别着急,现在还没有“净身”干净。现在的gcc对程序库和头文件的搜索路径还没有改变。即便采用specs大法也是有问题的,虽然它能够改变程序库的搜索路径,但是对头文件所搜路径的更改只是增加了一个优先级。如果在指定的路径中找不到指定的头文件,则依然会从宿主系统中寻找,这样依然无法保持工具链的纯净。所以,还是需要进行一番改造。方法是将gcc/config路径下的linux.h及gcc/config/i386路径下的linux.h、linux64.h和sysv4.h这四个文件中对程序库的搜索路径进行修正,增加/toolchain,并在它们的结尾处,添加一些宏定义。
修改是这样的:寻找所有类似“/lib/ld”、“lib64/ld”或“lib32/ld”这样的代码,它们一般都具备“/usr”的开头,如果有这个开头,就用“/toolchain”替换,没有就添加“/toolchain”。添加的宏定义如下面所示:

#undef STANDARD_INCLUDE_DIR
#define STANDARD_INCLUDE_DIR 0
#define STANDARD_STARTFILE_PREFIX_1“”
#define STANDARD_STARTFILE_PREFIX_2“”

注意,每个文件都要添加。
另外要补充说明一下。第一次生成gcc时采用的是交叉编译法,而这次被称为本地编译法。本地编译法默认会采用bootstrap方式进行。这种方式会重复生成三次。就是用第一次生成的gcc再一次编译自己,然后用第二次生成的gcc再重复一次。最后比较第二次和第三次的结果,这样来确保编译器可以毫无差错地编译自身。这是有点很浪费时间的,出于节省时间的考虑,我们要禁止使用这种方式。不过禁用bootstrap方式会有一个代价,就是无法享有-fomit-frame-pointer优化所带来的性能提升,这会导致后面的编译过程所需时间加剧。所以需要使用一个鱼与熊掌兼得的方法,强制使用-fomit-frame-pointer优化。技巧是修改该gcc/Makefile.in文件,在“T_CFLAGS=”的后面添加“-fomit-frame-pointer”。
好了,经过这么多的改造,就可以生成gcc了。不过这次会比第一次提供的功能多一些,而且也会生成C++编译器,因为后面需要。所使用的命令如下:

$ CC=“$x86_64-mgc3-linux-gnu-gcc-B/toolchain/lib/”\
AR=$x86_64-mgc3-linux-gnu-ar RANLIB=$x86_64-mgc3-linux-gnu-ranlib\
../gcc-4.6./configure--prefix=/toolchain\
--with-local-prefix=/toolchain—enable-clocale=gnu\
--enable-shared—enable-threads=posix\
--enable-__cxa_atexit--enable-languages=c,c++\
--disable-libstdcxx-pch--disable-multilib\
--disable-bootstrap—disable-libgomp\
--without-ppl—without-cloog\
--with-mpfr-include=$(pwd)/../gcc-4.6./mpfr/src\
--with-mpfr-lib=$(pwd)/mpfr/src/.libs
$ make-j
$ make install

解释一下之前没有见过的参数:
--with-local-prefix=/toolchain
这个参数的目的是把/usr/local/include目录从gcc的头文件搜索路径中删除。这也是让它与宿主系统相隔绝的一个环节。
--enable-clocale=gnu
因为这次引入了C++编译器,这个参数是为了确保C++程序库在任何情况下都使用正确的local模块。因为选择了不正确的locale模块有可能会导致C++库文件的ABI不兼容。
Enable-shared
这个参数是为了能够正确生成glibc所必须的。因为前面我们已经做了一个假的libgcc_eh.a文件来欺骗glibc了,但是到了生成正式系统时就不能用骗的了。
--enable-threads=posix
这个参数使得C++异常能处理多线程代码。
--enable-__cxa_atexit
这个参数允许使用_cxa_atexit代替atexit来注册C++对象的本地静态和全局析构函数。这是为了完全符合标准对析构函数的处理规定。它会影响到C++的ABI,这确保了生成的C++共享库和C++程序在其他的Linux系统上也能使用。
--disable-bootstrap
这就是用来禁用bootstrap方式的选项。
现在一个全新的独立于任何系统的gcc就生成了,拥有c和c++两个编译器。最后要执行一个画龙点睛的操作,创建一个cc到gcc的符号连接。这可以保持通用性,因为很多程序和脚本寻找的是cc而不是gcc。

16.2.8 丰富工具链的功能
现在我们的工具链已经具备了编译器、连接器和程序库,它们都是针对3.1.6内核的,并且已经独立于宿主系统。但是为了能够最终生成我们的目标系统,还需要对它进行一些完善。这需要表16-1所列出的这些软件包。

表16-1

软件包

说明

Tcl-8.5.10

这个东西跟电视机没什么联系,是工具命令语言的缩写。主要给后面的测试程序提供支持

Expect-5.45

一个以Tcl语言作为核心的工具。它可以使得需要交互的程序具备非交互特性,比如passwd。很多测试框架都是从于它来实现功能

DejaGNU-1.5

这是一个测试框架。使用Tcl语言编写,需要Expect的支持

Check-0.9.8

与DejaGNU类似,这是一个针对C语言的单元测试框架

Ncurses-5.9

非常著名的字符界面库。可以在字符界面实现窗口的绘制等

Bash-4.2

Linux下最为流行的shell,也是Linux的标准shell。所有Linux系统都应该提供

Bzip2-1.0.6

一个基于bzip2算法的压缩解压缩工具。所有以.bz2结尾的文件都使用它来解压缩

Coreutils-8.14

Linux系统的核心工具包。比如rm、mkdir、Is等都出自这个软件包

Diffutils-3.2

文件比对工具,经常用于生成补丁文件  diff命令

File-5.09

检测文件类型的工具

Findutils-4.4.2

就是著名的find工具    find命令

Gawk-4.0.0

Awk语言,编写shell脚本时经常使用。用于处理文本文件

Gettext-0.18.1.1

系统的国际化和本地化的工具。Linux多国语言支持就靠它了

Grep-2.10

非常著名的基于正则表达式的文本搜索程序

Gzip-1.4

基于gzip算法的压缩和解压缩工具。所有以.gz结尾的文件需要使用它来解压缩

M4-1.4.16

这是一个宏处理器,并内置了很多宏。是很多自动化工具的基础设施

Make-3.82

非常著名的make工具

Patch-2.6.1

非常著名的打补丁工具,它的补丁文件来源于diff工具

Perl-5.14.2

非常经典的Perl语言

Sed-4.2

这是一个流式文本编辑器。用途非常多,主要用在shell脚本修改文本文件的场景

Tar-1.26

Tar包管理程序

软件包

说明

Texinfo-4.13a

一整套info文档工具。Linux除了man帮助,还有更为详细的info文档

Xz-5.0.3

这是一个基于LZMA算法的压缩与解压缩工具。有很高的压缩比。以.xz结尾的文件使用它来解压缩

Linux下help、man、info命令区别详解

http://jingyan.baidu.com/article/75ab0bcbc7da3cd6874db26d.html
--help、man、info三个指令均为Linux下的帮助指令格式,三个指令略有区别。

help命令用于显示shell内部的帮助信息。help命令只能显示shell内部的命令帮助信息。而对于外部命令的帮助信息只能使用man或者info命令查看。
man命令,通过man指令可以查看Linux中的指令帮助、配置文件帮助和编程帮助等信息。man是在程序安装的时候安装的帮助文档,可以在系统的目录下找到,如果软件有配套的页面,就可以使用man来查找。
比如通过指令:ls /user/share/man我们可以看到很多man帮助文档的存储,我们从中看到有很多歌man#文件,linux的一些man指令文档就存在于这些文件内。

一个程序的man帮助文档可能存在多个man中,比如我们用指令:whatis man,查看到man的多个信息。而wahtis ifconfig说明ifconfig指令的帮助文档存在于man8中。
whatis ifconfig
ifconfig (8) - configure a network interface

我们用man ifconfig查看ifconfig的帮助文档,我们看到ifconfig左上角在man8中找到的相应帮助信息。而指令man man发现man在man1中就找到了,说明man手册是按顺序查找的。

info指令是man 指令的详细内容。但man 使用起来要方便的多。一个man 只有一页,而info总是将它们的内容组织成多个区段(节点),每个区段也可能包含子区段(子节点)。info工具可显示更完整的最新的GNU工具信息。通常man中若包含的信息概要在info中也有时,会有提示:“请参考info页更详细内容”。

这些软件的编译安装都比较简单。需要注意的地方是:第一,Tcl、Expect、DejaGNU这三个软件的安装顺序不能变,因为有一定的依赖关系;第二,Check和Ncurses的安装没有必然顺序,但是必须保证Nucrses是在其他软件之前安装,因为有一些软件依赖于它;第三,如果想要对这些软件的正确性进行测试,则必须最先安装Tcl、Expect、DejaGNU和Check,因为它们提供了测试用的框架。
有一些软件安装后要做一些调整。Tcl安装完毕之后,为了保持最大兼容性,需要创建一个“tclsh”到“tclsh8.5”的符号连接。因为当前版本的Tcl只安装tclsh8.5作为它的可执行程序,但是好多软件使用tclsh来调用Tcl。Bash安装后需要创建一个“sh”到“bash”的符号连接,因为作为默认shell,很多软件是直接调用“sh”而不是“bash”的。安装Coreutils软件包后,su命令不会被安装,因为在普通用户权限下不能安装su命令。这就需要手动复制到工具链中。但是为了保证可以使用宿主系统的su命令,需要将它重新命名。
还有一些软件在执行configure程序时需要使用一些参数来屏蔽或开启某些功能,或者干脆修改configure程序来保证它针对于工具链的纯粹和有效。Expect的configure程序会强制它使用/usr/local/bin/stty,但是在我们用工具链创建目标系统时这个程序路径是不对的,所以找到这段内容,修改成/bin/stty。编译Ncurses时,应该关闭对ada语言的支持,因为工具链就没提供这个语言。同时还要使用--enable-overwrite选项强制它将头文件安装到/toolchain/include路径下,这可以保证其他软件能够找到它。编译Bash时使用--without-bash-malloc参数来禁止使用它本身提供的malloc函数,因为它有访问越界bug。编译Coreutils时要使用--enable-install-program=hostname参数,因为默认它是不安装hostname这个工具的,但是Perl需要它。编译Grep时需要使用--disable-perl-regexp参数来禁用Perl兼容的正则表达式,因为在编译目标系统时它不能使用。同时还要使用--without-included-regex参数(pcre库 perl compatible regular expression),因为如果不使用这个参数会破坏目标系统的glibc的正则表达式库。
另外,在编译Perl的时候需要做一些比较大的改动。主要是修改hints/linux.sh文件。将所有涉及/lib/libc.so.6或/lib/$libc的内容要冠以/toolchain前缀。还要在它的末尾添加如下内容:

locincpth=“”
loclibpth=“”
glibpth=“/toolchain/lib”
usrinc=“/toolchain/include”

这是为了保证它只使用工具链的头文件和库。

16.2.9 整理工具链
此时此刻,我们的工具链就已经打造完成了。不过还需要做最后的调整,这个过程或许你认为没什么必要。但是这么费力打造的工具链是完全不止用于编译最终的Linux系统的,它还可以做好多好多有意义的工作。所以为了便于移动和交流,对它进行必要的精简是非常有意义的一件事情。
现在这个工具链能够精简哪些内容呢?首先就是调试信息。Linux上的软件通过源代码编译安装的,大多都会带有调试信息。这个调试信息非常庞大,往往比整个工具链还要大上几倍。而且工具链的调试信息对我们使用它的人也没什么意义,所以这个需要清理。
另外一个需要清理的内容就是工具链中各种工具的帮助信息。这些信息也会占据很大的磁盘空间,而且也没有什么实际用途。这些帮助信息可以在很多地方找得到。况且工具链需要运行在宿主系统中,往往宿主系统会提供这些帮助信息,所以工具链中的帮助信息就更加没有什么用处了。
所使用的命令如下:

# strip--strip-debug/toolchain/lib64/*
# strip--strip-unneeded/toolchain/{,s}bin/*
# rm-rf/tools/{,share}/{info,man,doc}

最后记得将toolchain目录的拥有者所属组都更改为root。这样可以防止工具链被破坏。而且接下来的过程将会一直使用root账户。虽然我很反对使用root,但是这是使用root的最好用例,因为这是要从头到尾编译Linux,那不也正是体现出root的原本含义的吗?

16.2.10 小结
一个完整的工具链打造完毕了。这个需要花费极大的耐心和时间。但是工具链是非常有用的。你能想到工具链都能做什么吗?
有没有想过,当一个全新的硬件平台开发出来,如何给它安装操作系统和软件呢?这个时候需要工具链。用工具链来编译目标平台的操作系统和软件,最终使得这个新的硬件平台具备了完整的软硬件体系。
一些没有操作系统的硬件平台如何为它们开发软件呢?比如诺基亚的非智能手机。这个时候需要工具链,在宿主系统上开发和编译能够运行在它上面的软件。这里最常见的宿主系统就是Windows。诺基亚会提供给开发者一个工具链,用来开发能运行在他们手机上的软件。
一些具备操作系统,但是没有足够大的屏幕,也没有鼠标键盘的智能系统如何给他们开发软件呢?比如大红大紫的Android智能手机。我们开发者都会从Google下载一个SDK,在Windows、Linux乃至Mac上开发Android程序。这个SDK也是一个工具链。
工具链是一个跨操作系统,跨硬件平台开发的必备工具,也是想成为一名优秀程序员的必修课程。我们在创建这个工具链的时候发现,需要对编译器、连接器甚至一些辅助的工具程序进行大量修改。也正因为这样,当我们在研究创建工具链的时候,会对这些程序做很深的研究才能达成我们的目标。这也就使得我们在研究工具链的时候,有足够的理由去深入研究那些平时我们用得最多,但不了解其内部运作机理的程序。当你把这些都研究透彻之后,是不是以后遇到一些开发上的问题,就会驾轻就熟呢?
好了,针对工具链的探讨就到此结束了。我们接下来还有很长的一段路需要走。你应该选择休息一会儿再继续下面的内容。

16.3 生成目标系统的运行环境
从现在开始,就真正开始了编译Linux系统的历程,而且要使用root身份。或许在开始这一部分内容的时候,你就开始打Linux内核的主意了。不过这会让你有些失望。现在还不是碰Linux内核的时候。这一阶段所要做的事情是准备运行环境。主要是将工具链中的“四角恋”转移到我们的目标系统中,并且创建一个可以正常运行的Linux系统的最小环境集合。可以把这部分内容看做是为我们即将出生的Linux打造一张温暖的床。
另外。为了能够让我们自己编译的Linux系统具备通用性,就需要让这个系统符合LSB规范。LSB是Linux Standards Base的缩写。不过LSB只是Linux标准化领域中的事实标准,因此就目前的Linux世界来看,它依然是有些混乱的。但是如果能够符合LSB,那么由于它已经是一个事实,所以就可以做到最大程度的通用化。至于LSB都规定了什么,我们后面章节再做介绍。通过接下来的内容,可以先体会一下LSB。

http://www.cnblogs.com/MYSQLZOUQI/p/5383594.html

16.3.1 准备工作
首先要做的准备工作就是准备特种文件系统(还记得“特种文件系统”那一章的内容吗?)。在我们准备好的磁盘分区上先要创建dev、proc、sys这三个目录。
创建好三个目录后,执行下面的命令:

# mknod-m  文件权限  /mnt/m13/dev/console c 字符设备
# mknod-m /mnt/m13/dev/null c

“mknod”这个命令是什么作用我不多解释,大家可以man一下,实在不行Google一下。执行完这两个命令之后,会在dev目录下生成“console”和“null”这两个重要的设备文件。这是为了保证在udevd启动之前,或者Linux以init=/bin/bash启动时,这些设备节点可以使用。
接着就是填充/dev目录的内容。这个时候目标系统还没有udev,所以它里面什么都没有,但是后面的步骤还非常需要它。怎么办呢?使用宿主系统的/dev。用下面的命令:

# mount-v--bind/dev/mnt/m13/dev

这是很典型的绑定挂接应用,我们之前说过,希望你现在还记得。然后把其他的特种文件系统都挂接到正确的位置:

# mount-vt devpts devpts/mnt/m13/dev/pts
# mount-vt tmpfs shm/mnt/ml3/dev/shm
# mount-vt proc proc/mnt/m13/proc
# mount-vt sysfs sysfs/mnt/m13/sys

既然pts和shm都已经在dev目录下了,为什么还要挂接一次呢?回想一下绑定挂接的特性就明白了。接下来地步骤更为重要,因为我们要进入chroot环境来构建这个新生的Linux系统的运行环境。chroot是一个程序,能够临时改变系统的根目录。正是利用这个特性,才使得我们可以很容易地构建目标系统的运行环境。使用如下命令进入这个chroot环境:

# chroot“/mnt/m13/”/toolchain/bin/env-i\   /sbin/service脚本也是这样
HOME=/root TERM=“$TERM”PSl=‘\u:\w\$’\
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/toolchain/bin\
/toolchain/bin/bash--login +h

这其中的第一个参数很显然地就是将我们准备的磁盘分区作为新的根目录来使用了,所以这个命令执行完毕之后,我们的磁盘分区就会成为根目录。
env命令的参数“-i”是清除chroot的环境变量,这就保证目标系统不会受到宿主系统的影响。同时设置了新的HOME、TERM和PSl这三个变量。HOME是直接指定的,所以与宿主系统没有关系。TERM使用了宿主的TERM内容,但是它不会对目标系统产生影响。PSl就是用于修改命令提示符的,随便你怎么设定。
有一个很有趣的设定就是PATH变量,它与宿主系统的PATH变量相反,/toolchain/bin放在了最后,原理与宿主的PATH相同,因为随着我们的努力,工具链应该被逐步取代。
最后的参数是让chroot环境使用工具链的bash作为shell,并且增加了“+h”这参数来保证chroot环境的纯碎。
当这条命令执行完毕之后,你会有一个吃惊的发现。命令提示符会显示成“I have no name!”。如果是这样就证明做对了,因为没有创建/etc/passwd文件就会有这样的提示符出现。
正确进入了chroot环境后,就需要创建目标系统的文件布局了。这个布局在LSB中是有规定的。执行下列命令:

# mkdir-pv/{bin,boot,etc/opt,home,lib,mnt,opt}
# mkdir-pv/{media/{floppy,cdrom},shin,srv,var}
# install-dv-m /root
# install-dv-m /tmp/var/tmp
# mkdir-pv/usr/{,local/}{bin,include,lib,sbin,src}
# mkdir-pv/usr/{,local/share/{doc,info,locale,man}
# mkdir-v/usr/,{,local/}share/{misc,terminfo,zoneinfo}
# mkdir-pv/usr/{,local/}share/man/man{..} man1~man8
# for dir in/usr/usr/local;do
In-sv share/{man,doc,info}$dir
done
# In-sv lib/lib64 && In-sv lib/usr/lib64
# mkdir-v/var/{lock,log,mail,run,spool}
# In-run/var/run
# In-sv/run/lock/var/lock
# mkdir-pv/var/{opt,cache,lib/{misc,locate},local}

有一些程序使用了固化的绝对路径,但是这些内容目前还不存在。为了应付这些程序,我们就用符号连接或空文件来“骗它”。当然,等到对应的软件被编译并安装之后,这些符号连接或空文件会被真实的文件所替换掉。执行下列命令:

# In-sv/toolchain/bin/{bash,cat,echo,pwd,stty}/bin
# In-sv/toolchain/bin/perl/usr/bin
# In-sv/toolchain/lib/libgcc_s.so{,.}/usr/lib
# In-sv/toolchain/lib/libstdc++.so{,.}/usr/lib
# In-sv bash/bin/sh
# touch/etc/mtab

为了让我们的命令提示符能够正常一点,还需要创建/etc/passwd和/etc/group这两个文件。当前没有什么文本编辑器可以用,只能用命令来完成:

# cat>/etc/passwd<<“EOF”
root:x:::root:/root:/bin/bash
bin:x:::bin:/dev/null:/bin/false
nobody:x:::Unprivileged User:/dev/null:/bin/false
EOF
# cat>/etc/group<<“EOF”
root:x::
bin:x::
sys:x::
kmem:x::
tty:x::
tape:x::
daemon:x::
floppy:x::
disk:x::
lp:x::
dialout:x::
audio:x::
video:x::
utmp:x::
usb:x::
cdrom:x::
mail:x::
nogroup:x::
EOF

这两个文件的内容没有什么严格规定,只要符合格式就好。如果想让这两个文件的内容看上去很专业,可以参考宿主系统的内容。
要想改变命令提示符,需要重新登录才行,执行:
# exec/toolchain/bin/bash--login +h
还要创建一些日志文件,因为没有它们,是无法记录日志的。执行下列命令:

# touch/var/run/utmp/var/log/{btmp,lastlog,wtmp}
# chgrp-v utmp/var/run/utmp/var/log/lastlog
# chmod-v /var/run/utmp/var/log/lastlog

其中:/var/run/utmp文件记录当前登录的用户;/var/log/wtmp文件记录所有的登录和退出;/var/log/lastlog记录每个用户最后的登录信息;/var/loglbtmp文件记录错误的登录尝试。
最后我们要将Linux的联机帮助信息(那个“男人”啊)安装好。执行下面的命令:

# cd sources
# tar vxf man-page-3.35.tar.gz
# cd man-page-3.35
# make install

它必须在所有软件安装前被安装好。因为只要稍晚一些安装它,它就会将之前编译安装的软件的联机帮助信息覆盖掉。其他软件不会有这样的结果,它们会丰富它的内容。

16.3.2 安装glibc
现在开始为目标系统安装必要的软件。第一个就是glibc,因为它是所有软件能够被编译并安装的基础。
首先还是要安装内核的API头文件,命令如下:

# make mrproper
# make headers_check
# make INSTALL_HDR_PATH=dest headers_install
# find dest/include\(-name.install-o-name..install.cmd\)-delete
# cp-rv dest/include/*/usr/include/

注意文件复制路径的改变。而且这次也删除了没有必要的垃圾文件。
不过现在还不能马上安装glibc。有一个小问题,就是当我们编译完成后,执行安装操作时,会执行一个叫做test-installation.pl的脚本来做一些完整性测试。可是我们是使用工具链来编译glibc的,这个完整性测试会对工具链中的glibc做测试,这会导致错误。因此我们在安装glibc之前,要对test-installation.pl脚本做一些调整,强制让它测试我们要安装的glibc。另外,这个脚本还有一个bug,我们也一同修正它。由于这个环境没有编辑器,所以需要执行必要的命令来进行修改。命令如下:

# DL=$(readelf-l/bin/sh|sed-n’s@.*interpret.*/toolchain\(.*\))$@\@p’)
# sed-i“s|libs-o|libs-L/usr/lib-Wl,-dynamic-linker=$DL-o}”\
scripts/test-installation.pl
# unset DL
# sed-i-e‘s“dbl”/&\&\&$name ne“nss_testl”/’

scripts/test-installation.pl
这些命令都干了些啥,我就不讲解了,想知道其中的秘密就好好学sed。这个东东在Linux系统中地位很重要。
接下来就可以安装glibc了,命令如下:

#../glibc-2.14./configure --prefix=/usr\
--disable-profile—enable-add-ons\
--enable-kernel=2.6
# make-j
# cp-v../glibc-2.14./iconvdata/gconv-modules iconvdata
# make -k check >&|tee glibc-check-log -k忽略错误,继续编译
# touch/etc/ld.so.conf
# make install

可以看得出编译选项已经少了很多了。多出来的步骤是用于对glibc进行一次全方位的测试。复制文件是为了保证测试能够顺利完成。生成/etc/ld.so.conf这个空文件是为了保证在安装glibc时它不会报错。当glibc安装完毕后,我们还要对它进行必要的配置。
首先就是对不同语言的支持,使用如下命令:

# mkdir-pv/usr/lib/locale
# localedef-i cs_CZ-f UTF- cs_CZ.UTF-
# localedef-i de_DE-f ISO-- de DE
# localedef-i de_DE@euro-f ISO-- de_DE@euro
# localedef-i de_DE-f UTF- de_DE.UTF-
# localedef-i en_HK-f ISO-- en_HK
# localedef-i en-PH-f ISO-- en_PH
# localedef-i en_US-f ISO-- en_US
# localedef-i en_US-f UTF- en_US.UTF-
# localedef-i es_MX-f ISO-- es_MX
# localedef-i fa_IR-f UTF- fa_IR
# localedef-i-i fr_FR-f ISO-- fr_FR
# localedef-i fr_FR@euro-f ISO-- fr_FR@euro
# localedef-i fr_FR-f UTF- fr_FR.UTF-
# localedef-i it_tT-f ISO-- it_IT
# localedef-i ja_JP-f EUC-JP ja_JP
# localedef-i tr_TR-f UTF- tr_TR.UTF-
# localedef-i zh_CN-f GB18030 zh_CN.GB18030
# localedef-i zh_CN-f UTF- zh_CN.UTF-

多说几句。在我国有一个强制标准,就是任何上市发行的简体中文软件,必须支持GB 18030编码。为了使得我们这个全新的Linux系统符合我国标准,我添加了对GB 18030的支持。不过我们最常使用的还是UTF-8,所以这个也被添加进去了。

目前国内用得最多:gbk/gb2312 ,gb2312 包含于gbk ,Gbk 是 gb18030 的子集,gbk 包含中日韩 通杀亚洲语言
utf8 utf8mb4
centos mysql 实战 第六节课 字符集 多字节 三码统一 继承 常见的字符集有哪些呢 存储长度 看看国内大厂都在用什么字符集 字符集配置 字符集转换 怎么避免乱码
http://www.cnblogs.com/MYSQLZOUQI/p/5406343.html

然后是创建/etc/nsswitch.conf和/etc/ld.so.conf文件。nsswitch.conf文件确保glibc在网络环境下能够良好的工作。ld.so.conf文件用来配置共享库的搜索路径。默认情况下,是在/lib、/lib64、/usr/lib和/usr/lib64这几个目录下搜索,但是如果想添加新的搜索路径,必须修改这个文件。现在使用如下命令编辑它们:

# cat>/etc/nsswitch.conf<<“EOF”
passwd:files
group:files
shadow:files
hosts:files dns
networks:files
protocols:files
services:files
ethers:files
rpc:files
EOF
# cat>/etc/ld.so.conf<<“EOF”
/usr/local/lib
/usr/local/lib64
/opt/lib
/opt/lib64
EOF

最后是修改时区。通过类似这样的命令:

# cp-V--remove-destination/usr/share/zoneinfo/<xxxx>/etc/localtime

命令中的<xxxx>内容,可通过tzselect命令确认。

16.3.3 调整工具链
当前我们的工具链所生成的程序还不能使用新的glibc,所以需要做一番调整。为什么我们选择在安装并配置好glibc之后来调整工具链呢?首先要感谢一下glibc的完全生活自理能力,这使得用目前的工具链来编译的glibc不会有任何依赖问题,也使得将工具链中的“四角恋”转移到目标系统中成为比较容易进行的事情。
还记得最后一次在工具链中生成binutils时,留下来的那个小尾巴吗?就是那个ld-new!现在该它登场了。执行如下命令:

# my-v/toolchain/bin/{ld,ld-old}
# my-v/toolchain/$(gcc-dumpmachine)/bin/{ld,ld-old}
# my-v/toolchain/bin/{ld-new,ld}
# In-sv/toolchain/bin/ld/toolchain/$(gcc-dumpmachine)/bin/ld

真是“明修栈道,暗渡陈仓”啊!然后还要修改specs文件,只不过这次没有编辑器可以用了,用命令吧:

# gcc-dumpspecs|sed-e’s@/toolchain@@g’\
-e’/\*startfile_prefix_spec:/{n;s@.*@/usr/lib64/@}’\
-e’/\*cpp:/{n;s@$@-isystem/usr/include@}’>\
‘dirname$(gcc—print-libgcc-file-name)‘/specs

这次修改的地方稍微有些不同,就是更改startfile_prefix_spec的配置信息。
修改完毕后,执行一下测试,查看一下相关的依赖都已经转移到了新的系统上面来。如果没有什么问题。就可以继续了。

16.3.4 安装binutils
这里要比制作工具链时要简单很多了。执行下列命令:

#../binutils-2.22/configure--prefix=/usr—enable-shared
# make tooldir=/usr
#make-k check
# make tooldir=/usr install
# cp-v../binutils-2.22/include/libiberty.h/usr/include

这一系列命令还是非常好理解的。可能有些疑惑的是make的参数“tooldir=/usr”。但是认真看本书的都知道这是Makefile的变量。tooldir这个变量的值在Makefile中是$(exec_prefix)/$(target_alias)。在这个场景中,就是/usr/x86_64-unknow-linux-gnu。我们肯定不希望我们的目标系统的/usr目录里有特殊的子目录。所以就利用命令行方式将它覆盖掉。
为了保证我们安装的binutils没有问题,在安装之前一定要进行测试。如果在这个过程中发现了太多的错误,一定是工具链出现了问题。最悲催的情况就是需要重新建立工具链。
libiberty.h这个头文件被很多软件使用。但是它不会被安装,所以需要手动将它复制到合适的位置。

16.3.5 安装gcc
这次我们编译gee时,要与在创建工具链时有很大不同了。
首先,gmp、mpfr和mpc这三个软件的源码不需要与gcc的源码合并了,而是直接在目标系统中安装它们。
其次,在编译gcc之前,还要先安装zlib。如果不这么做,gcc会用自己的实现。可是它自己的实现并不会安装到系统中。然而,有好多软件需要使用zlib提供功能。那么zlib就必须安装。为了保持目标系统的一致性,所有软件都统一使用一份zlib,那么就要求gcc使用由系统提供的zlib来代替它自己的实现。
最后,还要禁止gcc安装它自己的libiberty.a,因为在安装binutils的时候已经有了。
我们最先开始安装zlib。命令如下:

# tar vxf zlib-1.2..tar.bz2
# cd zlib-1.2.
# sed-i‘s/ifdef_LARGEFILE64_SOURCE/ifndef_LARGEFILE64_SOURCE/’zlib.h
# CFLAGS=‘-mstackrealign-fPIC-’./configure--prefix=/usr
# make
# make check
# make install

需要修改zlib.h文件是因为有一处笔误,需要将它修正过来。给configure程序提供CFLAGS变量,是因为默认的优化选项会导致运行时错误。
然后是安装gmp。命令如下:

# tar vxf gmp-5.0.
# cd gmp-5.0.
# sed-i‘s/np+dn,qn/&-dn/’mpn/generic/dcpil_bdiv_q.c
#./configure--prefix=/usr--enable--cxx--enable-mpbsd
# make
# make check >&|tee gmp-check-log
# make install
# mkdir-v/usr/share/doc/gmp-5.0.
# cp-v doc/{isa_abi_headache,configuration}doc/*.html\
/usr/share/doc/gmp-5.0.2

这里使用sed的是修正测试时的一个bug。由于gmP不会安装它的帮助文档,所以我们手工复制一下。
然后是安装mpfr。命令如下:

# tar vxf mpfr-3.1.
# cd mpfr-3.1.
#./configure--prefix=/usr-enable—thread-safe\
--docdir=/usr/share/doc/mpfr-3.1.
# make
# make check
# make install
# make html
# make install-html

最后是安装mpc。命令如下:

# tar vxf mpc-0.9.tar.bz2
# cd mpc-0.9
./configure--prefix=/usr
# make
# make check
# make install

Gmp、mpfr和mpc三者之间需要按照这个顺序进行安装,因为它们有这个依赖关系。待它们都安装好后。就可以安装gcc了。命令如下:

# tar vxf gcc-4.6..tar.bz2
# cd gcc-4.6.
# sed-i‘s/install_to_$(INSTALL_DEST)//’libiberty/Makefile.in
# sed-i‘s/ΛT_CFLAGS=$/&-fomit-frame-pointer/’gcc/Makefile.in
# sed-i‘s@\./fixinc\.sh@-c true@’gcc/Makefile.in
# mkdir../gcc-build
# cd../gcc-build
# ../gcc-4.6./configure--prefix=/usr
--libexecdir=/usr/lib—enable-shared\
--enable-threads=posix—enable-__cxa_atexit\
--enable-clocale=gnu—enable-languages=c,c++\
--disable-multilib-disable-bootstrap--with-system-zlib
# make-j
# make-k check
# make install
# In-sv../usr/bin/cpp/lib64
# In-sv gcc/usr/bin/cc

这些命令中:第一个sed禁止gcc生成自己的libiberty.a;第二个sed强制添加-fomit-frame-pointer优化;第三个是禁用fixinclude脚本:configure的--with-system-zlib这个参数使得gcc使用系统提供的zlib,也就是我们最开始安装的zlib;最后面创建的两个符号连接是为了保持系统的兼容性,因为很多软件会用它们。
当gcc安装完毕后,紧密的“四角恋”就在目标系统中建立起来了。这个时候我们就可以利用目标系统的编译器、连接器和程序库编译并安装其他的基础设施了。
顺便说一句,安装完毕后,不要忘记测试一下“四角恋”是否真的已经在目标系统中建立起来了。方法与建立工具链时使用的是相同的。

16.3.6 安装其他基础设施
作为一个能够独立运行的Linux系统,还需要如下的软件包:

表16-2

软件包

说明

File-5.09

检测文件类型的工具  file命令

Sed-4.2

这是一个流式文本编辑器。用途非常多,主要用在shell脚本修改文本文件的场景

Bzip2-1.0.6

一个基于bzip2算法的压缩解压缩工具。所有以.bz2结尾的文件都使用它来解压缩

Ncurses-5.9

非常著名的字符界面库。可以在字符界面实现窗口的绘制等

Util-linux-2.20.1

一个Linux工具集,其中包括处理文件系统、控制台、磁盘分区和信息的工具。Mount、fdisk、mkswap等工具出自这个软件包

Psmisc-22.14

进程管理工具包,fuser、killall、pstree等工具出自这个软件包

E2fsprogs-1.42

ext2文件系统工具箱,比如mkfs.ext2、fsck.ext2等。同一系列的ext3、ext4文件系统的管理工具亦出自这个软件包

Coreutils-8.14

Linux系统的核心工具包。比如rm、mkdir、is等都出自这个软件包

Iana-Etc-2.30

提供两个文件/etc/protocols和/etc/services。这两个文件提供了网络服务和协议的配置数据

软件包

说明

M4-1.4.16

这是一个宏处理器,并内置了很多宏。是很多自动化工具的基础设施

Bison-2.5

词法分析程序生成器,就是GNU版的yacc,

Bison是Inception服务所依赖的包之一
pgsql和mysql的安装都依赖bison和flex

Procps-3.2.8

利用/proc特种文件系统的,提供进程管理的程序包。著名的ps、kill,free,sysctl等命令就出自这个软件包

Grep-2.10

非常著名的基于正则表达式的文本搜索程序

Readline-6.2

提供命令行编辑和历史记录功能的库集合,pgsql的客户端psql需要上下翻页和历史命令功能依靠的是readline这个库

Bash-4.2

Linux下最为流行的shell,也是Linux的标准shell。所有Linux系统都应该提供

Libtool-2.4.2

GNU通用库支持脚本,将使用动态库的复杂性隐藏在统一的、可移植的接口中

GDBM-1.10

GNU数据库管理器。这是一个单文件的Key-Value数据库

Inetutils-1.8

包含基础网络程序的程序包。著名的ping和telnet就出自这个软件包

Perl-5.14.2

非常经典的Perl语言

Autoconf-2.68

Autotools工具之一。能生成用于自动配置源代码的shell脚本。我们一直在使用的configure程序就是它的“杰作”

Automake-1.11.2

与Autoconf配合使用,用于产生Makefile文件

Diffutils-3.2

文件比对工具,经常用于生成补丁文件

Gawk-4.0.0

Awk语言,编写shell脚本时经常使用。用于处理文本文件

Findutils-4.4.2

就是著名的find工具

Flex-2.5.35

一个词法分析程序生成器。是GNU版的lex,

Bison是Inception服务所依赖的包之一
pgsql和mysql的安装都依赖bison和flex

Gettext-0.18.1.1

系统的国际化和本地化的工具。Linux多国语言支持就靠它了

Groff_1.21

包含一些处理和格式化文本的程序

GRUB-1.99

我们要使用的多系统引导加载程序

Gzip-1.4

基于gzip算法的压缩和解压缩工具。所有以.gz结尾的文件需要使用它来解压缩

IPRoute2-3.1.0

包含了基本的和高级的基于IPv4网络的程序。比如ifcfg、rtmon等工具就出自这个软件包

Kbd-1.15.2

键盘映射表和键盘工具

Less-444

文本查看器less  less命令

Make-3.82

非常著名的make工具

Xz-5.0.3

这是一个基于LZMA算法的压缩与解压缩工具。有很高的压缩比。以.xz结尾的文件使用它来解压缩

Man-DB-2.6.0.2

Linux的在线手册工具包。著名的man就来自这里

软件包

说明

Module-Init-Tools-3.16

Linux内核可加载模块管理工具

Patch-2.6.1

非常著名的打补丁工具,它的补丁文件来源于diff工具

Shadow-4.1.4.3

安全方式下处理密码的程序包。著名的useradd、usermod、passwd等命令就出自这里。

Sysklogd-1.5

系统日志守护进程

Sysvinit-2.88dsf

控制系统启动、运行和关闭的程序包。著名的init进程就来自这里

Tar-1.26

Tar包管理程序

Texinfo-4.13a

一整套info文档工具。Linux除了man帮助,还有更为详细的info文档

Udev-173

利用/sys特种文件系统,在用户空间实现设备管理的软件包

Vim-7.3

著名的文本编辑器,属于Linux的默认编辑器,很多工具会调用它作为编辑器使用,比如visudo、crontab -e

这些软件构成了一个最小的Linux系统运行环境。可能它们之间会有一些依赖关系。但是按照表16-2中给出的顺序进行编译安装没有发现任何问题。

16.3.7 系统启动脚本
此时此刻系统的软件环境已经准备好了,但是这些软件该如何协调,乃至这些软件与系统的硬件如何协调使用还是一个很大的问题。解决这个问题就要请出系统启动脚本,见表16-3。

表16-3

脚本

说明

checkfs

在系统启动阶段,对即将要挂接的文件系统进行完整性检查。日志文件系统和基于网络的文件系统除外

cleanfs

在系统重启或关闭阶段,删除不需要保存的文件。

例如在/var/run/和/var/lock/目录下的文件;

重新创建/var/run/utmp文件并删除可能存在的/etc/nologin、/fastboot、/forcefsck文件

console

为指定的键盘布局读入正确的键盘映射表,并设置屏幕字体

consolelog

设置内核日志级别来控制信息到达控制台

functions

包含在不同脚本*用的一些函数,例如错误和状态检查函数

halt

关闭系统

ifdown

协助network脚本停止网络设备

脚本

说明

ifup

协助network脚本启动网络设备

localnet

设置系统主机名和本地回环(loopback)设备

modules

加载/etc/sysconfig/modules目录列出的内核模块,使用的参数也会在这个目录给出

mountfs

系统启动阶段,挂接所有文件系统,有noauto标记或者基于网络的文件系统除外

mountkernfs

系统启动阶段,加载虚拟内核文件系统,比如proc

network

配置网络接口,如网卡,并设置默认网关(如果可用)

rc

提供命令行编辑和历史记录功能的库集合

reboot

重新启动系统

sendsignals

在系统重启或关闭系统之前,确保每一个进程都已经终止了

setclock

如果硬件时钟没有设置为UTC时间,将内核时钟重置为本地时间

static

提供为网络接口指派静态IP地址的功能

swap

启用或禁用交换文件和交换分区

sysctl

如果/etc/sysctl.conf存在,将该文件的系统配置数据加载到运行的内核中

sysklogd

启动或停止系统和内核日志守护进程

template

为其他守护进程创建自定义启动脚本的模板

udev

启动udev并在/dev目录创建设备节点

udev_retry

如果需要,重试失败的udev消息,并从/dev/.udev拷贝通用的规则文件到/etc/udev/rules.d

需要提醒大家注意的是,表16-3只是在大体上给出了一个Linux系统在启动或关闭过程可能需要执行或必须执行的操作。这貌似是在说“车轴辘话”。之所以这样,是因为LSB只规定了Linux的启动或关闭的方式,并没有规定在启动或关闭的过程都要做些什么。而且基于不同目的的Linux系统,在启动或关闭阶段所要执行的操作也会有很大差别,所以这里是不能给出明确答案的。要想让自己的系统能很快运行起来,最好的一个办法就是复制宿主系统中的那些启动脚本。至于它们的工作原理,本书在前面的章节已经讲过了。

16.3.8 结束语
经过这一阶段,我们就具备了一个Linux系统可运行的基本环境。不过到目前为止,我们最为关键的“人物”还没有登场。那就是Linux内核。只有具备了内核,一个操作系统才能真正地工作起来。稍微休息一下,我们接下来就开始打造Linux内核。

16.4 定制Linux内核
经过这么一系列的折腾,终于开始内核的编译工作了。
Linux内核是非常开放滴,所以每一个Linux系统都可以有一个不同的内核。这就好比我们人类,每个人都有属于自己的心,是善、是恶、是美、是丑,那些都只是别人的标准。跟随着你的心,走你自己的路,只要能够感到快乐就足够了。当然,你的快乐不能建立在别人的痛苦之上,毕竟你不是在独行。生命中总是会有一个他/她陪伴着你。不管他/她是近、是远、是离、是合……
不由地开始抒情起来。我们还是回到正题。说说Linux的内核。编译Linux内核实际上也是定制Linux内核。这被很多人看来是一件非常神秘的事情。其实Linux内核的开发者们已经做了很多工作,帮助我们能够轻松愉悦地完成这个过程。其实比较难的就是取舍。所以很多时候还是需要英明决断一下的。那就跟着你的心,决定Linux的“心”好了。

16.4.1 内核的make参数
Linux内核的定制、编译乃至安装都是通过make工具来完成的。本书已经给大家灌输过了,通过Makefile的参数可以决定make做什么。那么我们就先看看Linux内核都提供了哪些Makafile参数。
● mrproper
这个参数在之前已经见到过了。它的作用是让Linux内核的源代码干干净净的。之所以需要做这个操作,是因为无法确定下载的源代码是否有保留的目标文件和一些相关的配置文件存在。为了保证能够彻头彻尾地对内核进行定制,就需要将那些目标文件和配置文件清理干净。需要注意的是,这个参数会将你以前的配置信息也删除掉。所以这个参数一般只应用在对某个版本内核的首次定制和编译的时候。其他情况下请使用clean参数。因为这个参数仅要求删除一些类似目标文件,而不会删除配置信息。这个很重要,千万不要弄乱。毕竟配置好一个版本的内核是比较辛苦的一个过程。
● menuconfig
这个参数是定制Linux内核时最常用的参数。它在文本模式下提供了一个基于窗口交互的配置界面。这个功能需要ncurses库的支持(之前我们已经提供过了)。另外一个常用的定制内核参数是oldconfig。它是利用已存在的老版本内核的配置信息作为预设值,仅将新版本内核的新功能列出让定制者选择的一种方式,这可以极大简化内核的定制过程。与之同类的参数还有xconfig和gconfig,这个两个参数都提供了一个基于图形交互的配置界面,前者基于QT,后者基于Gtk。最古老也没人使用的是config参数。将内核的配置项一条一条地列出,选错了只能重头再来。
● bzlmage
最常用的编译Linux内核参数。给定这个参数后,编译出来的内核镜像是压缩过的。具体使用什么压缩算法在定制阶段指定。比较不常用或根本不用的是vmlinux,编译出来的内核镜像未经压缩。只有对目标硬件环境非常了解,对Linux内核非常了解,且需要极快的启动速度时,才会考虑使用该参数。
● modules
编译内核可加载模块。Linux内核只提供了这一个参数用来编译可加载模块,所以也没什么好选择的。
● modules_install
安装内核可加载模块。也没什么好选择的。不过你可能会联想到参数install是用来安装内核镜像的。猜得不错,但是一般不用这个参数,因为它会修改启动记录。绝大多数Linux发行版使用GRUB,并不希望Linux内核自己完成引导过程,所以这个参数基本不用。
上述的这些参数是定制、编译和安装Linux内核最为常用的。如果对其他参数感兴趣,可以使用help参数来查看帮助信息。我在这里不做过多的介绍了。

16.4.2 定制界面
由于我们只提供ncurses,所以要完全彻底地定制Linux内核,只能使用menuconfig这个选项。那么我们就执行这个命令,看看定制界面是什么样的(见图16.2所示)。
# make menuconfig

Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统  nsswitch.conf配置文件

看到上面的图示之后,会发现Linux内核的配置界面主要分为三个部分。最上部是帮助信息;中部是设置项;下部是导航。中部和下部是主要的交互区域,从上部的帮助信息中可以了解如何操作这两个交互区域。这是一个类似“分层菜单”的交互界面。这是最顶层菜单。最顶层菜单的每个设置项,都会有多级菜单的子设置项。
使用“左右”方向键,可以移动下部的光标,选择<Select>、<Exit>和<Help>按钮;使用“上下”方向键,可以移动中部的光标,选择各个设置项;在设置项的开头如果出现有类似“[]”或“<>”这样的符号,表明该设置项是可选项,可以用“空格”键进行选择;若设置项的结尾处有“--->”这样的箭头,则表示该设置项还有若干子设置项,可以使用“回车”键进一步查看子设置项。如果在设置项前面出现类似“[*]”或“<*>”这样的符号,则表示该设置项对应的功能会直接编译进内核镜像:如果是“<M>”则表示该设置项对应的功能会被编译成可加载模块;在任何时候选按下部的<Exit>按钮,都会退出当前子设置项列表或退出配置界面。

这里在配置内核的时候有一些小小的建议。建议只使用“上下左右方向键、空格、回车”这六个按键就可以了。尽量不要使用Esc,因为可能一不小心就按错了。另外,对于整个内核功能上的选择,我也提供一点自己的见解:
1.确定是内核必须具备的功能,应该直接编译到内核镜像中。
2.不确定是内核必须具备的,但将来可能会用到的功能,尽量编译成可加载模块。
3.不知道干什么的功能,甚至查看help也搞不懂的功能,就保留预设值,或者将它们编译成可加载模块。

总之,尽量保持内核的小而美,余下的功能编译成可加载模块。如果就是自己玩玩,就不要举棋不定,当机立断最好。如果拿来跟别人分享,那么就尽量多考虑一些可扩展性,不过这也是最难抉择的。只有经验才一能赋予你足够强大的能力。
如果想进一步了解每个设置项所对应的功能,那么可以选按<Help>按钮查看相关的帮助信息。如果觉得帮助信息无法说明问题,那么最好的办法是问谷哥。正所谓:“内事问百度,外事问谷哥。”这里百度能帮上的忙有限。

16.4.3 编译与安装
当内核定制完毕后,就开始进行编译和安装操作了。一般执行下列命令:

# make bzImage
# make modules_install
# cp-v arch/x86/boot/bzlmage/boot/vmlinuz-3.1.-mgc3.x86_64
# cp-v.config/boot/config-3.1.
#cp-v System.map/boot/System.map-3.1.
# install-d/usr/share/doc/linux-3.1.
# cp-r Documentation/*/usr/share/doc/linux-3.1.6
# install-v-m755-d/etc/modprobe.d

这里需要说明一下的是System.map文件和/etc/modprobe.d这个目录。System.map文件是内核的符号文件。它映射了内核API中每个函数的入口,以及正在运行内核的数据结构的地址。在调试内核问题时,它是一种极其重要的资源。/etc/modprobe.d这个目录用于配置内核可加载模块的加载顺序。具体如何配置是根据内核本身定制的特性决定的,所以这里不再给出。希望了解的同学可以自行研究。

16.5 独立运行
十月怀胎,一朝分娩。我们满心期待的“婴儿”就要呱呱坠地了,我们需要彻底剪断“脐带”,让它*地呼吸在这个陌生的世界里。

16.5.1 /etc/fstab文件
不管你信不信,/etc/fstab文件都是让Linux系统能够独立运行的十分重要的文件。这个文件用来确定哪些文件系统被自动挂接。如果没有它,Linux系统将无法确认“根”文件系统,没有“根”怎么能立足呢?/etc/fstab文件不但决定了哪些文件系统被自动挂接,还决定了它们的挂接顺序以及是否需要进行挂接前的监测(主要是完整性校验)。它的内容一般类似这样:

# file system mount-point type options dump fsck
/dev/<xxx> / <fff> defaults
/dev/<yyy> swap swap pri=
proc /proc proc defaults
sysfs /sys sysfs defaults
devpts /dev/pts devpts gid=,mode=
tmpfs /dev/shm tmpfs defaults

只要将你系统上的适当值替换<xxx>、<yyy>和<fff>即可,比如sdal、sda2和ext3。有关文件中六个字段的详细介绍,可以参考“man 5 fstab”,且本书之前也介绍过了,这里不做复述。

16.5.2 使用GRUB配置启动过程
GRUB几乎成为Linux世界的标准引导程序,目前的绝大多数Linux发行版都使用GRUB作为引导器。也从这一点间接地证明了GRUB的强大之处。
在使用和配置GRUB的时候要注意,它使用自己的驱动器和分区命名方式。基本格式是这样的:(hdn,m),这里n是硬盘号,m是分区号。硬盘号从“0”开始,而分区号,对于主分区是从“1”开始,扩展分区则是从“5”开始。我还要提一句的是,当前版本的GRUB与老版本的有些差别,老版本的分区号也是从“0”开始的。将GRUB与Linux进行对应,如sda1就是(hd0,1),sdb3就是(hd1,3)。但是相对与Linux,GRUB不会将CD-ROM驱动器当作硬盘看待。所以,如果sdb是光驱,而sdc是另外一块硬盘的话,sdc在GRUB中依然是(hd1)。通过下面的命令可看一下GRUB是如何看待你的磁盘设备的:

# grub-mkdevicemap--device-ma=device.map
# cat device.map

每个人的设备不尽相同,所以我就不列出结果了,大家自己看就行了。
让GRUB工作,就是让它更改引导记录,并正确配置GRUB。方法也很简单,只要执行下面的命令:

# grub-install/dev/sda
# grub-mkconfig-o/boot/grub/grub.cfg

第一个命令就是将GRUB的引导记录写入MBR,我将设启动盘是第一个硬盘。第二个命令是自动生成配置文件,配置文件的路径是/boot/grub/grub.cfg。这就可以了。很多人还在想如何编写GRUB的配置文件吧?实际上是不用编写,一切都是自动完成的。
这时只要重新启动系统,就可以选择使用我们刚刚编译生成的Linux系统了。如果之前没有什么错误,肯定会是一个了不起的系统的。

16.6 结束语
到此,我终于将如何从头到尾编译Linux系统的整个过程展现给大家了。很多人或许希望能够在本章中一步一步地操作,并在本章结束时就能拥有一个自己的Linux系统。其实这是不现实的,因为编译这么大的一个工程是非常耗费时间的。在我的最新的Mac Book Pro电脑上要完成这个过程大概需要7个小时左右,显然这么长的时间没人会乐意花在看这种无聊的书上。因此我不得不做一个折中,只讲解那些关键的地方,并提供编译步骤和必备的软件给大家,并将原理传授给大家,希望大家读完本章后能够理解这些步骤的作用,以便将来参考LFS独立完成。

nsswitch.conf配置文件
http://blog.chinaunix.net/uid-20788470-id-1841614.html
今天在公司的服务器上/etc/resolves.conf文件中增加了DNS服务器IP地址, 但是发现还不解析域名, 搞的很郁闷, 后来找到一个同事,  原来是nsswitch.conf文件的hosts项的文件:
原来的:   hosts: files
修改后的:  hosts: files dns  #这表示对域名, 先用/etc/hosts文件解析, 解析不了再查dns
 
nsswitch.conf:服务搜索顺序
随着NIS和DNS的出现,查找用户信息和系统信息就不再是搜索本地文件这样简单的事情了。以前,查看/etc/passwd文件就可以获取用户信息,查看/etc/hosts文件就可以找到系统地址信息,而现在使用多种途径来查找这类信息。文件/etc/nsswitch.conf(name service switch configuration,名字服务切换配置)规定通过哪些途径以及按照什么顺序通过这些途径来查找特定类型的信息。还可以指定若某个方法奏效抑或失效系统将采取什么动作。
格式
文件nsswitch.conf中的每一行配置都指明了如何搜索信息,比如用户的口令。nsswitch.conf每行配置的格式如下:
info:         method [[action]] [method [[action]]...]
其中,info指定该行所描述的信息的类型,method为用来查找该信息的方法,action是对前面的method的返回状态的响应。action要放在方括号里面。
nsswitch.conf的工作原理
当需要提供nsswitch.conf文件所描述的信息的时候,系统将检查含有适当info字段的配置行。它按照从左向右的顺序开始执行配置行中指定的方法。 在默认情况下,如果找到期望的信息,系统将停止搜索。如果没有指定action,那么当某个方法未能返回结果时,系统就会尝试下一个动作。有可能搜索结束都没有找到想要的信息。
1. 信息
nsswitch.conf文件通常控制着用户(在passwd中)、口令(在shadow中)、主机IP地址和组信息的搜索。 下面的列表描述了nsswitch.conf文件控制搜索的大多数信息(前面所讨论的配置行格式中的info)的类型。
automount   自动挂载(/etc/auto.master和/etc/auto.misc)
bootparams  无盘引导选项和其他引导选项(参见bootparam的手册页)
ethers      MAC地址
group       用户所在组(/etc/group)
hosts       系统信息(/etc/hosts)
networks    网络信息(/etc/networks)
passwd      用户信息(/etc/passwd)
protocols   协议信息(/etc/protocols)
publickey   用于安全模式下运行的NFS
rpc         RPC名称和编号(/etc/rpc)
services    服务信息(/etc/services)
shadow      映射口令信息(/etc/shadow)
 
2. 方法
下面列出了nsswitch.conf配置文件控制搜索的信息类型(前面所讨论的配置行格式中的method)。对于每一种信息类型,都可以指定下面的一种或者多种方法:
files       搜索本地文件,如/etc/passwd和/etc/hosts
nis         搜索NIS数据库,nis还有一个别名,即yp
dns         查询DNS(只查询主机)
compat      passwd、group和shadow文件中的±语法(参见本节后面的相关内容)
 
3. 搜索顺序
两个或者更多方法所提供的信息可能会重叠。举例来说,files和nis可能都提供同一个用户的口令信息。如果出现信息重叠现象,就需要考虑将哪一种方法作为权威方法(优先考虑),并将该方法放在方法列表中靠左的位置上。
默认nsswitch.conf文件列出的方法并没有动作项,并假设没有信息重叠(正常情况)。在这种情况下,搜索顺序无关紧要:当一种方法失败之后,系统就会尝试下一种方法,只是时间上受到一点损失。如果在方法之间设置了动作,或者重叠的项的内容不同,那么搜索顺序就变得重要起来。
下面几行取自nsswitch.conf文件,第一行让系统在/etc/passwd文件中搜索口令信息,如果失败的话,就使用NIS来查找信息。如果正在查找的用户同时出现在这两个地方,就会使用本地文件中的信息,因此它就是权威信息。第二行使用NIS搜索;如果失败的话,就搜索/etc/hosts文件;如果再次失败的话,核对DNS以找出主机信息。
 
4. 动作项
在每个方法后面都可以选择跟一个动作项,用来指定如果由于某种原因该方法成功抑或失败需要做些什么。动作项的格式如下:
[[!]STATUS=action]
其中,开头和末尾的方括号属于格式的一部分,并不是用来指出括号中的内容是可选的。STATUS(按照约定使用大写字母,但本身并不区分大小写)是待测试的状态,action是如果STATUS匹配前面的方法所返回的状态将要执行的动作。开头的感叹号(!)是可选的,其作用是将状态取反。
STATUS
 STATUS的取值如下。
l    NOTFOUND——方法已经执行,但是并没有找到待搜索的值。默认的动作是continue。
l    SUCCESS——方法已经执行,并且已经找到待搜索的值,没有返回错误。默认动作是return。
l    UNAVAIL——方法失败,原因是永久不可用。举例来说,所需的文件不可访问或者所需的服务器可能停机。默认的动作是continue。
l    TRYAGAIN——方法失败,原因是临时不可用。举例来说,某个文件被锁定,或者某台服务器超载。默认动作是continue。
 
action
 action的取值如下:
l    return——返回到调用例程,带有返回值,或者不带返回值。
l    continue——继续执行下一个方法。任何返回值都会被下一个方法找到的值覆盖。
 
示例
举例来说,下面这行取自nsswitch.conf文件,它的作用是让系统首先使用DNS来搜索给定主机的IP地址。DNS方法后面的动作项是测试该方法所返回的状态是否为“非(!)UNAVAIL”。
如果DNS方法没有返回UNAVAIL(!UNAVAIL),也就是说DNS返回SUCCESS、NOTFOUND或者TRYAGAIN,那么系统就会执行与该STATUS相关的动作(return)。其结果就是,只有在DNS服务器不可用的情况下才会使用后面的方法(files)。如果DNS服务器并不是不可用(两次否定之后就是“可用”),那么搜索返回域名或者报告未找到域名。只有当服务器不可用的时候,搜索才会使用files方法(检查本地的/etc/hosts文件)。
 
5. compat方法:passwd、group和shadow文件中的“±”
可以在/etc/passwd、/etc/group和/etc/shadow文件中放入一些特殊的代码,(如果在nsswitch.conf文件中指定compat方法的话)让系统将本地文件和NIS映射表中的项进行合并和修改。
在这些文件中,如果在行首出现加号(+),就表示添加NIS信息;如果出现减号(-),就表示删除信息。举例来说,要想使用passwd文件中的这些代码,可以在nsswitch.conf文件中指定passwd: compat。然后系统就会按照顺序搜寻passwd文件,当它遇到以+或者-开头的行时,就会添加或者删除适当的NIS项。
虽然可以在passwd文件的末尾放置加号,在nsswitch.conf文件中指定passwd: compat,以搜索本地的passwd文件,然后再搜寻NIS映射表,但是更高效的一种方法是在nsswitch.conf文件中添加passwd: file nis而不修改passwd文件。

 cat /etc/nsswitch.conf
#
# /etc/nsswitch.conf
#
# An example Name Service Switch config file. This file should be
# sorted with the most-used services at the beginning.
#
# The entry '[NOTFOUND=return]' means that the search for an
# entry should stop if the search in the previous entry turned
# up nothing. Note that if the search failed due to some other reason
# (like no NIS server responding) then the search continues with the
# next entry.
#
# Valid entries include:
#
# nisplus Use NIS+ (NIS version )
# nis Use NIS (NIS version ), also called YP
# dns Use DNS (Domain Name Service)
# files Use the local files
# db Use the local database (.db) files
# compat Use NIS on compat mode
# hesiod Use Hesiod for user lookups
# [NOTFOUND=return] Stop searching if not found so far
# # To use db, put the "db" in front of "files" for entries you want to be
# looked up first in the databases
#
# Example:
#passwd: db files nisplus nis
#shadow: db files nisplus nis
#group: db files nisplus nis passwd: files
shadow: files
group: files #hosts: db files nisplus nis dns
hosts: files dns # Example - obey only what nisplus tells us...
#services: nisplus [NOTFOUND=return] files
#networks: nisplus [NOTFOUND=return] files
#protocols: nisplus [NOTFOUND=return] files
#rpc: nisplus [NOTFOUND=return] files
#ethers: nisplus [NOTFOUND=return] files
#netmasks: nisplus [NOTFOUND=return] files bootparams: nisplus [NOTFOUND=return] files ethers: files
netmasks: files
networks: files
protocols: files
rpc: files
services: files netgroup: nisplus publickey: nisplus automount: files nisplus
aliases: files nisplus
cat /etc/protocols
# /etc/protocols:
# $Id: protocols,v 1.9 // :: ovasik Exp $
#
# Internet (IP) protocols
#
# from: @(#)protocols 5.1 (Berkeley) //
#
# Updated for NetBSD based on RFC , Assigned Numbers (July ).
# Last IANA update included dated --
#
# See also http://www.iana.org/assignments/protocol-numbers ip IP # internet protocol, pseudo protocol number
hopopt HOPOPT # hop-by-hop options for ipv6
icmp ICMP # internet control message protocol
igmp IGMP # internet group management protocol
ggp GGP # gateway-gateway protocol
ipencap IP-ENCAP # IP encapsulated in IP (officially ``IP'')
st ST # ST datagram mode
tcp TCP # transmission control protocol
cbt CBT # CBT, Tony Ballardie <A.Ballardie@cs.ucl.ac.uk>
egp EGP # exterior gateway protocol
igp IGP # any private interior gateway (Cisco: for IGRP)
bbn-rcc BBN-RCC-MON # BBN RCC Monitoring
nvp NVP-II # Network Voice Protocol
pup PUP # PARC universal packet protocol
argus ARGUS # ARGUS
emcon EMCON # EMCON
xnet XNET # Cross Net Debugger
chaos CHAOS # Chaos
udp UDP # user datagram protocol
mux MUX # Multiplexing protocol
dcn DCN-MEAS # DCN Measurement Subsystems
hmp HMP # host monitoring protocol
prm PRM # packet radio measurement protocol
xns-idp XNS-IDP # Xerox NS IDP
trunk- TRUNK- # Trunk-
trunk- TRUNK- # Trunk-
leaf- LEAF- # Leaf-
leaf- LEAF- # Leaf-
rdp RDP # "reliable datagram" protocol
irtp IRTP # Internet Reliable Transaction Protocol
iso-tp4 ISO-TP4 # ISO Transport Protocol Class
netblt NETBLT # Bulk Data Transfer Protocol
mfe-nsp MFE-NSP # MFE Network Services Protocol
merit-inp MERIT-INP # MERIT Internodal Protocol
dccp DCCP # Datagram Congestion Control Protocol
3pc 3PC # Third Party Connect Protocol
idpr IDPR # Inter-Domain Policy Routing Protocol
xtp XTP # Xpress Tranfer Protocol
ddp DDP # Datagram Delivery Protocol
idpr-cmtp IDPR-CMTP # IDPR Control Message Transport Proto
tp++ TP++ # TP++ Transport Protocol
il IL # IL Transport Protocol
ipv6 IPv6 # IPv6
sdrp SDRP # Source Demand Routing Protocol
ipv6-route IPv6-Route # Routing Header for IPv6
ipv6-frag IPv6-Frag # Fragment Header for IPv6
idrp IDRP # Inter-Domain Routing Protocol
rsvp RSVP # Resource ReSerVation Protocol
gre GRE # Generic Routing Encapsulation
dsr DSR # Dynamic Source Routing Protocol
bna BNA # BNA
esp ESP # Encap Security Payload
ipv6-crypt IPv6-Crypt # Encryption Header for IPv6 (not in official list)
ah AH # Authentication Header
ipv6-auth IPv6-Auth # Authentication Header for IPv6 (not in official list)
i-nlsp I-NLSP # Integrated Net Layer Security TUBA
swipe SWIPE # IP with Encryption
narp NARP # NBMA Address Resolution Protocol
mobile MOBILE # IP Mobility
tlsp TLSP # Transport Layer Security Protocol
skip SKIP # SKIP
ipv6-icmp IPv6-ICMP # ICMP for IPv6
ipv6-nonxt IPv6-NoNxt # No Next Header for IPv6
ipv6-opts IPv6-Opts # Destination Options for IPv6
# # any host internal protocol
cftp CFTP # CFTP
# # any local network
sat-expak SAT-EXPAK # SATNET and Backroom EXPAK
kryptolan KRYPTOLAN # Kryptolan
rvd RVD # MIT Remote Virtual Disk Protocol
ippc IPPC # Internet Pluribus Packet Core
# # any distributed file system
sat-mon SAT-MON # SATNET Monitoring
visa VISA # VISA Protocol
ipcv IPCV # Internet Packet Core Utility
cpnx CPNX # Computer Protocol Network Executive
cphb CPHB # Computer Protocol Heart Beat
wsn WSN # Wang Span Network
pvp PVP # Packet Video Protocol
br-sat-mon BR-SAT-MON # Backroom SATNET Monitoring
sun-nd SUN-ND # SUN ND PROTOCOL-Temporary
wb-mon WB-MON # WIDEBAND Monitoring
wb-expak WB-EXPAK # WIDEBAND EXPAK
iso-ip ISO-IP # ISO Internet Protocol
vmtp VMTP # Versatile Message Transport
secure-vmtp SECURE-VMTP # SECURE-VMTP
vines VINES # VINES
ttp TTP # TTP
nsfnet-igp NSFNET-IGP # NSFNET-IGP
dgp DGP # Dissimilar Gateway Protocol
tcf TCF # TCF
eigrp EIGRP # Enhanced Interior Routing Protocol (Cisco)
ospf OSPFIGP # Open Shortest Path First IGP
sprite-rpc Sprite-RPC # Sprite RPC Protocol
larp LARP # Locus Address Resolution Protocol
mtp MTP # Multicast Transport Protocol
ax. AX. # AX. Frames
ipip IPIP # Yet Another IP encapsulation
micp MICP # Mobile Internetworking Control Pro.
scc-sp SCC-SP # Semaphore Communications Sec. Pro.
etherip ETHERIP # Ethernet-within-IP Encapsulation
encap ENCAP # Yet Another IP encapsulation
# # any private encryption scheme
gmtp GMTP # GMTP
ifmp IFMP # Ipsilon Flow Management Protocol
pnni PNNI # PNNI over IP
pim PIM # Protocol Independent Multicast
aris ARIS # ARIS
scps SCPS # SCPS
qnx QNX # QNX
a/n A/N # Active Networks
ipcomp IPComp # IP Payload Compression Protocol
snp SNP # Sitara Networks Protocol
compaq-peer Compaq-Peer # Compaq Peer Protocol
ipx-in-ip IPX-in-IP # IPX in IP
vrrp VRRP # Virtual Router Redundancy Protocol
pgm PGM # PGM Reliable Transport Protocol
# # any -hop protocol
l2tp L2TP # Layer Two Tunneling Protocol
ddx DDX # D-II Data Exchange
iatp IATP # Interactive Agent Transfer Protocol
stp STP # Schedule Transfer
srp SRP # SpectraLink Radio Protocol
uti UTI # UTI
smp SMP # Simple Message Protocol
sm SM # SM
ptp PTP # Performance Transparency Protocol
isis ISIS # ISIS over IPv4
fire FIRE
crtp CRTP # Combat Radio Transport Protocol
crdup CRUDP # Combat Radio User Datagram
sscopmce SSCOPMCE
iplt IPLT
sps SPS # Secure Packet Shield
pipe PIPE # Private IP Encapsulation within IP
sctp SCTP # Stream Control Transmission Protocol
fc FC # Fibre Channel
rsvp-e2e-ignore RSVP-E2E-IGNORE
# # Mobility Header
udplite UDPLite
mpls-in-ip MPLS-in-IP
manet manet # MANET Protocols [RFC5498]
hip HIP # Host Identity Protocol
shim6 Shim6 #Shim6 Protocol [RFC5533]
# - Unassigned [IANA]
# Use for experimentation and testing [RFC3692]
# Use for experimentation and testing [RFC3692]
# Reserved [IANA]
cat /boot/grub/grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You have a /boot partition. This means that
# all kernel and initrd paths are relative to /boot/, eg.
# root (hd0,)
# kernel /vmlinuz-version ro root=/dev/sda2
# initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=
timeout=
splashimage=(hd0,0)
/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.-.el6.x86_64)
root (hd0,)
kernel /vmlinuz-2.6.-.el6.x86_64 ro root=UUID=030f1baf-3cea-4c9a-838a-a45eb345e91b rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF- rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.-.el6.x86_64.img rpm -qa|grep grub
grub-0.97-93.el6.x86_64 旧版本的grub

/var/run/utmp 当前登录的用户
strings /var/run/utmp
reboot
2.6.32-504.el6.x86_64
runlevel
2.6.32-504.el6.x86_64
tty1
root
tty3
LOGIN
tty2
LOGIN
tty6
LOGIN
tty5
LOGIN
tty4
LOGIN
pts/0
ts/0root
192.168.1.106
pts/1

/var/log/wtmp  所有的登录和退出
strings /var/log/wtmp
reboot
2.6.32-504.el6.x86_64
9@WV
runlevel
2.6.32-504.el6.x86_64
9@WVh
tty2
LOGIN
?@WV
tty4
LOGIN
?@WV
tty5
LOGIN
?@WV
tty3

/var/log/lastlog  每个用户最后登录信息
strings /var/log/lastlog
Vpts/0
192.168.1.106
Vpts/1
192.168.1.155

/var/log/btmp  错误的登录尝试

Linux就这个范儿 第8章 我是Makefile

http://www.cnblogs.com/MYSQLZOUQI/p/5208438.html
8.4.2 命令
我猜想你到现在多少对命令有了一些了解,但是一定还有很多疑问并没有得到解答。比如我说过,命令实际上就是shell命令。
但是Linux的shell有很多种,能叫上名字的就有如:Bash、Korn shell、C shell等几种。那么make执行的是那个shell的命令呢?
是不是执行make命令时所采用的shell呢(比如你采用C shell作为默认shell)?
答案很给力,就是“/bin/sh”这个东西,别无它选。这个东西实际上就是bash,也是Linux世界中应用最为广泛的shell,而且任何Linux发行版都会提供。

f

Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统 nsswitch.conf配置文件的更多相关文章

  1. Linux就这个范儿 第15章 七种武器 linux 同步IO&colon; sync、fsync与fdatasync Linux中的内存大页面huge page&sol;large page David Cutler Linux读写内存数据的三种方式

    Linux就这个范儿 第15章 七种武器  linux 同步IO: sync.fsync与fdatasync   Linux中的内存大页面huge page/large page  David Cut ...

  2. Linux就这个范儿 第12章 一个网络一个世界

    Linux就这个范儿 第12章 一个网络一个世界 与Linux有缘相识还得从一项开发任务说起.十八年前,我在Nucleus  OS上开发无线网桥AP,需要加入STP生成树协议(SpanningTree ...

  3. Linux就这个范儿 第11章 独霸网络的蜘蛛神功

    Linux就这个范儿 第11章  独霸网络的蜘蛛神功  第11章 应用层 (Application):网络服务与最终用户的一个接口.协议有:HTTP FTP TFTP SMTP SNMP DNS表示层 ...

  4. Linux就这个范儿 第10章 生死与共的兄弟

    Linux就这个范儿 第10章 生死与共的兄弟 就说Linux系统的开机.必须经过加载BIOS.读取MBR.Boot Loader.加载内核.启动init进程并确定运行等级.执行初始化脚本.启动内核模 ...

  5. Linux就这个范儿 第9章 特种文件系统

    Linux就这个范儿 第9章 特种文件系统 http://book.douban.com/reading/32081222/ P326 有一种文件系统,根本不在磁盘上.这种文件系统就是大名顶顶的ram ...

  6. Linux就这个范儿 第8章 我是Makefile

    Linux就这个范儿 第8章 我是Makefile P287 Makefile的作用就是——自动化编译,一旦写好,只需要一个make命令(解析Makefile,执行Makefile中描述的操作),整个 ...

  7. Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式

    Linux就这个范儿 第18章  这里也是鼓乐笙箫  Linux读写内存数据的三种方式 P703 Linux读写内存数据的三种方式 1.read  ,write方式会在用户空间和内核空间不断拷贝数据, ...

  8. Linux就这个范儿 第19章 团结就是力量 LSB是Linux标准化基地&lpar;Linux Standards Base&rpar;的简称

    Linux就这个范儿 第19章 团结就是力量  LSB是Linux标准化基地(Linux Standards Base)的简称 这个图片好可爱,它是LSB组织的图标.你肯定会问:“图标这么设计一定有说 ...

  9. Linux就这个范儿 第14章 身在江湖

    Linux就这个范儿 第14章 身在江湖 “有人的地方就有江湖”,如今的计算机世界就像一个“江湖”.且不说冠希哥有多么无奈,把微博当QQ的局长有多么失败,就说如此平凡的你我什么时候就成了任人摆布的羔羊 ...

随机推荐

  1. LeetCode 368

    题目描述: Given a set of distinct positive integers, find the largest subset such that every pair (Si, S ...

  2. DbUtility v3

    DbUtility v3 历史 七年前,也就是2007年,我在博客园写了一篇博文,开源并发布了恐怕是我第一个开源项目,DbUtility.其设计的初衷就是为了简化ADO.NET繁琐的数据库访问过程,提 ...

  3. 通过btn获取所在cell

    [cell.btn addTarget:self action:@selector(cellBtnClicked:event:) forControlEvents:UIControlEventTouc ...

  4. NuGet学习笔记&lpar;1&rpar; 初识NuGet及快速安装使用

    关于NuGet园子里已经有不少介绍及使用经验,本文仅作为自己研究学习NuGet一个记录. 初次认识NuGet是在去年把项目升级为MVC3的时候,当时看到工具菜单多一项Library Package M ...

  5. (九)串行口方式0 拓展并行输入端口 74LS165 芯片

    74LS165芯片讲解: 外接一个同步移位寄存器 74LS165芯片,拓展一个 8 位 并行输入端口的电路, 可将接在74LS165芯片的8个开关 S0——S7 的状态 通过 串行口方式 0 读到 单 ...

  6. 编写2个接口:InterfaceA和InterfaceB;在接口InterfaceA中有个方法void printCapitalLetter&lpar;&rpar;;在接口InterfaceB中有个方法void printLowercaseLetter&lpar;&rpar;;然 后写一个类Print实现接口InterfaceA和InterfaceB,最后再在主类E 的main方法中创建Print的对象并赋值,运行方法

    package lianxi; public interface InterfaceA { void printCapitalLetter(); } package lianxi; public in ...

  7. AR增强现实特点、关键技术和应用

    http://wenku.baidu.com/link?url=ABXxm5yezMIQRJUV7XvNWUe_QpUUdpQ3IxGRpYUa760iex1_bygCcTBvEhCMvrdLAmSX ...

  8. java 代码格式(转)

    //转至博客:http://developer.51cto.com/art/201202/320317.ht /** * Java编码格式个人推荐,参考JDK源码和Hyperic HQ源码(原spri ...

  9. C&plus;&plus;对象模型2--指针cout结果

    在开始之前,首先科普一下cout指针的知识,这样才能在测试程序中很好的理解: 看下面的代码: void main(void) { int a = 10; int *p = &a; cout & ...

  10. 表迁移工具的选型-复制ibd的方法

    1.1. 场景 有的时候开放人员自己的库需要帮忙导一些数据,但是表的数据量又很大.虽然说使用mysqldump或mysqlpump也可以导.但是这耗时需要比较久. 记得之前建议开放人员可以直接使用na ...