2.4 让这个新的gcc环境能够真正的工作起来
编译器、连接器、程序库都创建好了,可以开始创建MagicLinux了吧?呵呵,不行!这个
新的gcc环境还没有真正工作起来呢。不信,我们做一个实验试试。编写一个最简单的C代码:
#echo 'main(){}' > ttt.c
#gcc ttt.c
#readelf -l a.out
看看结果,是不是有一行类似下面的内容:
[Requesting program interpreter:/lib/ld-linux.so.2]
这是不对的。readelf是分析elf可执行文件(Linux下可执行文件的格式)格式的工具,-l选项是
用来显示可执行文件各段头内容的,通过它可以了解一个可自行文件的依赖关系。上面的结果
表明新的gcc产生的可执行文件还是依赖于你现有系统的ld-linux.os.2,这是glibc的一部分。
这是为什么?该怎么办?
问题在创建binutils是就已经作了一些解决,但是还没有完全解决。回想一下,在安装完
binutils后,还做了如下操作:
#make -C ld clean
#make -C ld LIB_PATH=/toolchain/lib
#cp -v ld/ld-new /toolchain/bin
创建了一个ld-new,而且还复制到了/toolchain/bin下,这个ld-new就是关键,执行下面操作:
#mv -v /toolchain/bin/{ld,ld-old}
#mv -v /toolchain/$(gcc -dumpmachine)/bin/{ld,ld-old}
#mv -v /toolchain/bin/{ld-new,ld}
#ln -sv /toolchain/bin/ld /toolchain/$(gcc -dumpmachine)/bin/ld
这就使得接下来创建的程序都使用/toolchain/lib中的程序库了。可是为什么要现在才作上述
操作呢?因为在这之前,glibc还没有被创建,/toolchain/lib还不存在。
连接器搞定了,编译器还不行呢。这里我要多说几句。程序库分为两种,即静态库和动态
库。静态库就是在程序在被创建时由连接器确认它们的关系,并将它们组合在了一起成为一个
整体;动态库则不同,是在程序运行时,由动态连接器确认它们之间关系,它们是完全独立的
个体。这里不要将连接器和动态连接器弄混了,连接器是binutils提供的ld程序,而动态连接
器则是glibc提供的。连接器的名称通常是 ld-linux.so.2,在不怎么流行的平台上则可能是
ld.so.1,而在新的64位平台上更可能是别的完全不同的名称。为什么这时候编译器还不行呢?
因为编译器为了创建不同的程序,即要使用连接器也要使用动态连接器,所以要还要告诉编译
器动态连接器在哪里。现在的这个gcc还只是知道你所用系统的动态连接器的位置,你现在应
该告诉他新的在哪里。这是通过gcc的specs文件完成的。
通过下面的指令来产生gcc的specs文件:
#gcc -dumpspecs > `dirname $(gcc -print-libgcc-file-name)`/specs
直接将specs文件放入了它所起作用的位置。可以执行下面的命令获得这个路径:
#dirname $(gcc -printf-libgcc-file-name)
打开spces文件,修改所有类似“/lib/ld-linux.so.2”内容为
“/toolchain/lib/ld-linux.so.2”。你可以用任何你熟悉的方式作,我有一个简单的方法如
下:
#gcc -dumpspecs | sed 's@/lib/ld-linux.so.2@/tools&@g' \
> `dirname $(gcc -print-libgcc-file-name)`/specs
这几个程序简单的组合,利用管道和输出从定向机制,就完成了所有的操作。这就是类Unix系
统的精髓与魅力所在,各位读者体会一下,如果想了解更多Unix精髓,建议看一下《Unix编程
艺术》一书。
动态连接器问题解决了,还有一些麻烦问题需要处理,要不然,这个新的gcc环境还是对你
现在运行的系统有关系,因为gcc的fixincludes脚本在创建gcc的过程中,由于某些原因把你系
统里的头文件复制给这个新的gcc环境中去了。这就是好心办坏事,不过不用担心,是有办法挽
救的。执行下面的命令会将fixincludes产生的影响处理掉,当然,如果fixincludes没有帮倒
忙,下面的命令也不会作坏事,破坏这个新生的gcc环境:
#GCC_INCLUDEDIR=`dirname $(gcc -print-libgcc-file-name)`/include
#find ${GCC_INCLUDEDIR}/* -maxdepth 0 -xtype d -exec rm -rvf '{}' \;
#rm -vf `grep -l "DO NOT EDIT THIS FILE" ${GCC_INCLUDEDIR}/*`
#unset GCC_INCLUDEDIR
这下好了,马上检测一下:
#gcc ttt.c
#readelf -l a.out
如果你能看到如下结果就证明成功了:
[Requesting program interpreter:/lib/ld-linux.so.2]
如果没看到这样的结果,没办法了,从新创建gcc吧。注意查看一下你现在的PATH环境变量,是
否与“准备环境”一节相符。
最后,应该收一下尾了。
#rm -v ttt.c a.out
2.5 继续工作
这个时候你的全新的gcc环境可以工作了,但是我们前面说过,还需要再创建一次binutils
和gcc,这是因为你的binutils和c编译器还没有脱离你现有的系统,同时gcc也只支持c编译,
只是临时的过度产物。现在就要开始真正的工作了,这次创建的binutils和gcc真正的与你的系
统脱离了,而且你要用它们来完成接下来很多重要程序的创建工作。
这次的创建如此之重要,你需要保证创建完成的binutils和gcc可以很好的工作。不要以为
你可以凭借经验作到这些,或者手工编写一些简单的程序测试一下,这是一个浩大且复杂的工
程。你真正需要的是一些现有的工具,来检测你创建完成的程序是否能用。你也不用担心这些,
几乎每个重要的开源软件都包含了测试套件,但是这些套件需要一些工具的支持,所以,你在
第二次创建binutils和gcc之前,要准备好这样的工具。它们是Tcl、Expect和DejaGNU,它们
为大多数软件的测试套件提供了支持环境,所以不管怎么样,我都要建议你创建它们。
Tcl,呵呵,和你家的电视机没什么关系。Tcl是Tool Command Language的简称,即工具
命令语言。Tcl是一个种很通用的脚本语言,它几乎在所有平台上都可以解释运行,功能强大。
首先,Tcl是一种简单的脚本语言,主要用于发布命令给一些交互程序,如文本编辑器、调试器、
Shell等;其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器,不但用于
执行内建命令的例程,还可以使用你扩充(定义新的过程)的库函数。
Expect是Tcl的一个扩展,为某些交互程序提供了自动交互功能。现代的Shell对程序提
供了最小限度的控制(开始、停止等),而把交互的特性留给了用户。这意味着有些程序你不
能非交互的运行,比如说passwd。有一些程序可以非交互的运行,但在很大程序上丧失了灵活
性,比如fsck。这表明Unix的工具构造逻辑开始出现问题。Expect恰恰填补了其中的一些裂痕,
解决了在类Unix环境中长期存在着的一些问题。不仅如此,不管程序是交互的还是非交互的,
Expect都能运用。这是一个小语言和类Unix系统的其他工具配合起来产生强大功能的经典例子。
DejaGNU是一个测试程序框架,如果这么解释你不明白的话,可以说成是Framework,如
果还不能明白,可以说DejaGNU有点类似MFC,但是它们实现的语言和目的不同。DejaGNU就是
为前面所说的测试套件提供了一个统一的框架,它也是Tcl的一个扩展。
另外,补充一句,大部分软件包,都会包含测试工具的,建议你执行以下,这样可以保证
你发布的系统有很好的可用性。
没什么可说的,创建它们吧。
2.6 创建Tcl
目前最新版本的Tcl是8.5.0,但是Expect还没有跟上脚步,所以建议使用8.4.17。源代码
包可能是这样的名字:tcl8.4.17-src.tar.gz。创建Tcl大概需要5分钟左右的时间,占据24MB
左右的磁盘空间。
解压缩源代码包,并进入源代码目录:
#tar -zvxf tcl8.4.17-src.tar.gz
#cd tcl8.4.17
现在为创建Tcl作准备工作:
#cd unix
#./configure --prefix=/toolchain
开始创建:
#make
安装:
#make install
为了让Tcl的一些扩展程序能够被创建,还需要安装Tcl的头文件,执行下面的操作:
#make install-private-headers
为了兼容性,还需要创建一个符号连接,如下:
#ln -sv tclsh8.4 /tools/bin/tclsh
Tcl创建完毕了,可以进行下一步的操作了。别忘了收尾工作:
#cd ../../
#rm -rf tcl8.4.17
另外,如果你对这个刚刚创建的Tcl有些不放心的话,在执行安装步骤之前可以测试一下:
#TZ=UTC make test
这个过程不是必需的,因为Tcl的测试程序在某些环境下会失败,而且这个测试也并不是很关
键。TZ=UTC 参数将时区设置为协调世界时(UTC),也就是格林尼治时间(GMT),但只是在运行
测试程序的时候才这样设置,这将确保时钟测试正确。
2.7 创建Expect
目前最新版本的Expect是5.44,但是官方说5.44在重入上还有一些问题,建议使用5.43。
源代码包可能是这样的文件名:expect-5.43.0.tar.bz2。不过5.43也有bug,需要修复一下,
补丁文件可能是这样的文件名:expect-5.43.0-spawn-1.patch。
整个过程比较快,不到一分钟就能搞定,也只需要4~5MB的磁盘空间。
首先解压缩源代码,进入源代码目录:
#tar -jvxf expect-5.43.0.tar.bz2
#cd expect-5.43
打补丁,修Bug:
#pathc -Np1 -i ../expect-5.43.0-spawn-1.patch
为了让Expect也能够完全独立,还需要对它的configure文件做些修改:
#cp configure{,.bak}
#sed 's:/usr/local/bin:/bin:' configure.bak > configure
作准备工作:
#./configure --prefix=/toolchain --with-tcl=/toolchina/lib \
--with-tclinclude=/toolchain/include --with-x=no
各选项的含义是:
--with-tcl=/toolchain/lib
告诉configure脚本,Tcl解释器在哪里。这里要用刚刚创建的Tcl,否则就会使用你系
统的Tcl了。
--with-tclinclude=/toolchain/include
告诉configure脚本,Tcl的头文件位置。
--with-x=no
不使用X图形系统支持,因为没有Tk(Tcl的图形用户界面组件)。
开始创建:
#make
安装:
#make SCRIPTS="" install
安装选项的含义:
SCRIPTS=""
这个选项防止安装 Expect 所补充的一些并不需要的脚本。
最后作些收尾工作,回到sources目录下。
另外,与Tcl一样,在安装之前,可以测试一下:
#make test
但是这也是不必要的,同样在某些环境下会失败。
2.8 创建DejaGNU
最新版本是1.4.4。源代码包的文件名可能是:dejagnu-1.4.4.tar.gz整个过程不到一分
钟,需要6~7MB的磁盘空间。
解压缩源代码包,进入源代码目录:
#tar -zvxf dejagnu-1.4.4.tar.gz
#cd dejagnu-1.4.4
过程很简单,执行下列操作:
#./configure --prefix=/toolchain
#make install
你要测试的话,执行下面的操作:
#make check
最后别忘了收尾工作。
2.9 第二次创建gcc
测试工具都已经创建完毕并安装好了,现在就要开始第二次创建gcc和binutils了。这次的创
建将使它们连接到新的glibc,这样就与你的系统彻底脱离了。
另外,这些测试工具会受到伪终端的影响,如果设置不正确的话,它们是拒绝工作的。为
了保证这一点,你可以执行下列命令:
#expect –c “spawn ls”
如果你得到下面的结果:
The system has no more ptys.
Ask your system administrator to create more.
这就说明你系统的虚拟终端没有配制好,就不要尝试运行测试工具了,因为那没有什么意义。
至于如何设置虚拟终端,已经超过本文的范围,请查看相关专业文档。
闲话不多说,首先应该创建gcc,毕竟这是一个编译器集,让它先工作起来似乎比较让人感
到宽心。但这时候要注意的是,这次创建的gcc是独立于任何系统的,那么首先就要让它规矩的
一点,不要与任何系统有什么丝毫牵连。这里有一个惹祸的根苗——fixincludes脚本。在gcc的编
译过程会运行fixincludes脚本来扫描系统头文件目录,并找出需要修正的头文件,然后把修正后
的头文件放到gcc专属头文件目录里。另外,由于gcc专属头文件目录会被优先搜索,结果就是
gcc使用的头文件是你系统的头文件,而不是你新创建的那个。这个好心办坏事的东西,还是把
它除掉算了。通过修改gcc/Makefile.in文件来完成这个操作。将“./fixinc.sh”用“-c true”替换。简
单的命令行操作如下:
#cd gcc-4.2.2
#cp –v gcc/Makefile.in{,.orig}
#sed ‘s@\./fixinc\.sh@-c true@’ gcc/Makefile.in.orig \
> gcc/Makefile.in
同时,第一次创建gcc时采用的是bootstrap方式,这种方式不仅仅是创建gcc,而是重复创建它几
次。它用第一次创建生成的程序来第二次创建自己,然后又用第二次创建生成的程序来第三次
创建自己,最后比较第二次和第三次创建的结果,以确保编译器可以毫无差错的编译自身。在
这种模式下,会默认带有一个-fomit-frame-pointer编译选项,而在关闭bootstrap模式后,这个选项
也会被取消,为了确保在关闭bootstrap模式时同样开启-fomit-frame-pointer编译选项,我们需要手
工修改gcc/Makefile.in文件,在“XCFLAGS=…”的内容后面添加“-fomit-frame-pointer”,可以通
过下面简单的指令完成操作:
#cp –v gcc/Makefile.in{,.orig}
#sed ‘s/^XCFLAGS=$/& -fomit-frame-pointer/’ gcc/Makefile.in.tmp \
> gcc/Makefile.in
还有需要注意的是,这次应该让gcc缺省使用toolchain的glibc,而且默认搜索目录也不要再有
/usr/include了,为了保证这一点,需要执行下列操作:
#for file in $(find gcc/config -name linux64.h -o -name linux.h)
do
cp -uv $file{,.orig}
sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&@g' \
-e 's@/usr@/tools@g' $file.orig > $file
echo "
#undef STANDARD_INCLUDE_DIR
#define STANDARD_INCLUDE_DIR 0" >> $file
touch $file.orig
done
这比在创建完gcc再调整specs文件要好,这样可以保证新的动态连接器在这次创建gcc的时候就
用上。也就是说,随后的所有临时程序都会连接到新的glibc上。上述这些操作是非常重要的,
为了成功完成gcc的创建,一定要执行它们。
一切准备好好,进入正题吧。与第一次相同,还是要创建一个build目录:
#mkdir build
#cd build
做准备工作,执行configure脚本:
#../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-bootstrap
各选项的含义是:
--enable-clocale=gnu
这个参数确保C++库在任何情况下都能使用正确的locale模块。
--enable-threads=posix
该选项使得C++的异常处理为线程安全的。
--enable-__cxa_atexit
用__cxa_atexit代替atexit来登记C++对象的本地静态和全局析构函数,这是为了完
全符合对析构函数的处理规定。它还会影响到C++ABI,并且这使得生成的C++共享库在
其他的Linux发行版上也能使用。
--enable-languages=c,c++
同第一次一样,此时又加入了C++编译器的支持。
--disable-libstdcxx-pch
该选项使得不创建libstdc++预编译头(PCH),它占用了很大的空间,而且还用不到它。
--disable-bootstrap
该选项关闭bootstrap模式。目前的gcc是默认开启bootstrap模式的。
开始创建gcc:
#make
此时可以执行gcc的测试套件了,不过肯定会有错误的,因为它太过全面了:
#make –k check
这里的-k参数使得测试套件即使遇到错误也要继续运行,直到完成。接下来执行安装程序:
#make install
好了,这项重要的工作完成了。可以执行2.4章所介绍的测试方法测试一下,如果执行下列命
令后:
#readelf –l a.out
如果可以看到类似下面的内容:
[Requesting program interpreter:/lib/ld-linux.so.2]
这说明你的操作成功了,如果没有,你的麻烦就大了。
好了,你已经完成了gcc的第二次创建工作,可以继续下面的工作了,最后别忘了收尾工
作,毕竟磁盘空间很重要啊。此次你可以将gcc的源代码都删掉了。
2.10 第二次创建binutils
这次创建binutils的步骤与第一次基本一样:
#cd binutils-2.18
#mkdir build
#cd build
#../configure –prefix=/toolchain \
--disable-nls –with-lib-path=/toolchain/lib
#make
不太相同的是在执行configure脚本时,带有一个--with-lib-path选项。这个选项指示configure脚本
在binutils创建过程中将传递给连接器的库搜索路径设置为/toolchain/lib,也就是使用新创建的程
序库。
接下来测试套件可以发挥一下了:
#make check
现在就可以安装了:
#make install
最后我们还要再创建一次连接器ld,以待后面使用:
#make –c ld clean
#make –c ld LIB_PATH=/usr/lib:/lib
#cp –v ld/ld-new /toolchain/bin
至于这些操作的含义在第一次创建binutils时已经说明了,不再复述。不要忘了收尾工作,这次
你可以将binutils的源代码目录一同删除了。
2.11 锦上添花
到了这个阶段,你的toolchain制作算是告一个段落了。由于前面说过,glibc是自包含
的,在这里也不需要再次创建它了。所有的工具都与你的系统脱离了关系,编译器、连接器
和程序库它们之间也交织起来可以很好的完成本职工作了,而且你还有了功能强大的测试套
件支持工具。
虽然这样看起来不错,但是你的toolchain还不能脱离你现有的系统独立工作,除非你非
常厉害,不过我想不出这个世界上是否真的有这样厉害的人。为什么呢?首先,一个用C写成
的完整程序,很少只有一个源代码文件。它提供的所有文件都要编译一遍,还要将它们产生的
目标文件再用连接器一一将它们与程序库组合成最终的程序。我描述这些步骤就已经很复杂了,
你要是手工这么操作将会是什么结果?其次,好多源代码包提供不止一个工具,这些工具大多
数情况下会互相依赖,有时还要依赖已安装的软件包,这些依赖关系都需要你来维护,如果只
有一两个还好说,如果上千个呢?往往这个数量比你想象的还要多。另外,Linux的大多数软
件的源代码都提供了很好的可移植性,它们们可以运行于所有类Unix系统之上。虽然都属于类
Unix系统,但不同的产品有不同的特性,好多软件需要依赖这些特性。这往往需要利用预编译
器帮忙决定采用那些特性适合何种系统。如果这些内容通过手工解决的话,工作量很可能是一
个天文数字。由此可见,你现在的这个toolchain创建一个完整的软件系统没有任何问题,但是
需要付出根本无法估量的冗繁的操作步骤才能完成某个简单的软件包的创建过程。
懒惰是人类文明进步与发展的原动力。Unix世界的程序员经过几十年的不懈努力,艰苦卓
绝,前仆后继,发明并创造了一个又一个神奇而强大的工具,让他们自己、你、我和其他所有
人都因此而受益非浅。这其中就包括gcc、binutils和glibc,还有后面我将介绍给你的所有用
于这个toolchain的工具。
我首先要介绍给你的一个非常重要的工具——Make,它对于toolchain无比重要,毕竟你不
想一个文件一个文件的编译各种软件包。无论是在何种环境下make都是一个非常重要的软件创
建工具。不管是自己进行项目开发还是安装应用软件,你都经常要用到make或make install。
利用make工具,你可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百
个源文件的应用程序,使用make和makefile工具就可以简洁明快地理顺各个源文件之间纷繁复
杂的相互关系。而且如此多的源文件,如果每次都要键入gcc命令进行编译的话,那对程序员来
说简直就是一场灾难。而make工具则可以根据Makefile描述的规则自动完成编译工作,并且可
以只对程序员在上次编译后修改过的部分进行编译。因此,有效的利用make和makefile工具可
以大大提高项目开发的效率。同时掌握make和makefile之后,你也不会再面对着Linux下的应用
软件手足无措了。至于它们的详细内容已经超过本文的范围,感兴趣的读者可以参考有关专业
文档。
另外一个与创建软件包有关的工具是configure脚本。Linux上的软件大多是可以运行在其
他类Unix系统上的,而且它们之间或多或少的存在一些差异,这些差异对程序员是不透明的,
比如有的平台编译器文件名为cc,而有的可能是gcc,还有可能是其他别的什么。而且,即便
是在Linux上,不同的发行版本也可能存在一些差异,比如有些支持framebuffer,而有些可能
不支持。应用软件的作者为了使他们的软件尽可能的在大多数系统下都可以很好的工作,他们
要针对不同的环境作不同的处理,这些对于作者是没有问题的,可是将这些代码交付给用户,
让用户决定该如何取舍却是不可行的事情。因此,configure这个脚本工具就诞生了,它来检
测各系统间的差异性,然后修改相应的Makefile文件,决定做如何取舍。configure脚本是由
软件作者自己维护的,它清楚的知道在什么样的环境下,采用什么样的编译器、编译选项等内
容,而用户只需要执行一下这个脚本,就一切OK了。configure是完全使用shell脚本编写的,
几乎可以在所有类Unix系统中运行,这就保证了它的通用性。随着configure的发展,逐渐的扩
展了原有的功能,开始承担软件包的配置工作了,可以决定软件包的那些组件被创建,那些可
以不用创建等。而且人们还发明了用于产生configure的工具,使得原来很复杂的工作变得越
来越简单了。
前面介绍了Make工具和confiugre脚本。这两个重要的工具是你在创建Linux所有软件包必
不可少的工具,你永远也离不开它们,就像你离不开gcc、binutils和glibc一样,否则你就无
法进行MagicLinux的开发。使用Make需要configure改写Makefile文件,使用configure需要
shell来执行,shell来执行configure还需要更多的软件包来支持,它们是Ncurses、Bash、
Bzip2、Coreutils、Diffutils、Findutils、Gawk、Gettext、Grep、Gzip、Make、Patch、
Perl、Sed、Tar、Util-linux。除了Ncurses之外,其他的都是按照文件名排列的,因为它们
之间不存在太多必要的依赖关系。
Ncurses是最早的System V Release 4.0 (SVr4)中 CURSES的一个克隆。这是一个可自由
配置的库,完全兼容旧版本的curses。简而言之,它是一个管理应用程序在字符终端显示的函
数库。ncurses不仅仅封装了底层终端功能,而且提供了一个相当稳固的工作框架
(Framework),可以在字符模式下产生美观的界面。它提供了一些创建窗口的函数。而它的姊
妹库 Menu、Panel和Form则对curses基础库及进行了扩展。这些扩展库通常都随同curses一起
发行。可以建立一个同时包含多个窗口(multiple windows)、菜单(menus)、面板
(panels)和表单(forms)的应用程序。窗口可以被独立管理,例如让它滚动或者隐藏。
Linux系统下被广泛应用的shell——Bash就要依赖它完成字符界面的显示功能。
Bash是Bourne-Again Shell的缩写,这个 Shell 是 Bourne Shell 的增强版本,也是基
准于 GNU 的架构下发展出来的。第一个流行的 shell 是由 Steven Bourne 发展出来的,为了
纪念他所以就称为 Bourne shell,或直接简称为 sh。而后来另一个广为流传的 shell 是由柏
克莱大学的 Bill Joy设计依附于BSD版的Unix系统中的shell,这个shell的语法有点类似C语言,
所以才得名为C shell,简称为csh。由于在学术界 Sun 主机势力相当的庞大,而 Sun 主要是
BSD的分支之一,所以C shell也是另一个很重要而且流传很广的 shell 之一。Bash是GNU计划
中重要的工具软体之一,目前也是 GNU操作系统中标准的shell,他主要相容于sh。所以,可
想而知的,目前几乎所有的Linux发布都是使用bash作为管理核心的主要shell。如果没有
shell,configure脚本是无法执行的,也就无法创建各种软件包了。
Bzip2是块排序文件压缩器,使用Burrows-Wheeler块排列文本压缩算法和霍夫曼编码来
压缩文件。压缩比要大于gzip工具使用的基于LZ77/LZ78的压缩算法(如gzip格式),接近PPM统
计压缩算法族的压缩比。Linux的大部分软件的源代码包的文件名有.bz2,这就表明它使用了
bzip2进行的打包压缩,需要bzip2来解压缩。
Coreutils如其名称一样,是一个核心工具包。包含如:cp、ls、mkdir、cat等常用的
shell命令。为了使你的toolchain在各种环境下都可以独立工作,你需要它拥有这些常用命令。
Diffutils这个软件包里的程序向你显示两个文件或目录的差异,常用来生成软件的补丁。
它包括cmp、diff、diff3和sdiff,这些工具在很多时候很有用处,你的toolchain应该拥有它们。
Findutils软件包包含查找文件的工具,既能即时查找(递归的搜索目录,并可以显示、
创建和维护文件),也能在数据库里查找(通常比递归查找快但是在数据库没有及时更新的情况
下,结果并不可靠)。configure脚本在做一些系统检测时会用到,所以你的toolchain一定要
包含这个软件包。
Gawk是GNU所做的awk,Gawk 最初在1986年完成,之后不断地被改进、更新。Gawk包含
awk的所有功能。awk是一个程序设计语言,有很强的数据处理能力。对于文本文件里的内容做
修改、比对、抽取等处理时,awk能够以很短的程序轻易完成。如果使用C或Pascal等语言写程
序来完成上述的动作,不但不方便还需要花费大量时间,所写的程序也会很大。awk能够依照
使用者定义的格式来分解输入的数据,也可依照使用者定义的格式来输出数据。至于awk的语
法等内容的说明已经超出本文的范围,请读者阅读专业著作。
Gettext是实现程序国际化和本地化的一种工具。最初,在美国,程序通常都采用英语
编写,界面和文档都用英文表述。这是很自然的事情,因为他们日常使用的就是英语。如果
这些程序只被习惯使用英语的人使用,这本身也是很正常的事,不需要有什么改变。然而,
慢慢地,事情有了一些变化,许多的程序,不仅需要被习惯说英语的人使用,也需要被其他语
种的人使用,比如中文,日文,德文等。这些不使用英语作为母语的人,他们更希望程序的界
面或文档,能够以他们自己更加熟悉的语言表示。那么,有没有一种方法呢?这种方法可以让
程序支持多种语言,而且可以很方便地切换语言环境,由一种语言转换到另一种语言。正是基
于这种目的,翻译项目试图研究出可行的工作方案,解决这个问题,让人们有机会开发出真正
的多语言程序。gettext是翻译项目的重要一步,它提供了一个工作框架,由一些集成的工具
和文档组成,帮助程序员、翻译人员和最终用户实现程序的国际化和本地化。需要说明的是,
gettext只是实现此目标的一种方法,还有其他方法的存在。如果你的toolchain要支持多语言,
gettext是非常明智的选择。
Grep(global search regular expression(RE) and print out the line,全面搜索正
则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把
匹配的行打印出来。Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep
有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,
它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,
不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用
egrep和fgrep的功能。Shell脚本在缺少grep支持的时候,几乎寸步难行。
Gzip是GNU zip的缩写,它是一个 GNU 自由软件的文件压缩程序。gzip 的基础是
DEFLATE,DEFLATE 是 LZ77 与哈夫曼编码的一个组合体。文件名以.gz结尾的源代码包就是采
用Gzip压缩和解压的。
Make就不用多说了,前面已经有很详细的介绍了,没有它你将寸步难行。
Patch是前面介绍的Diffutils软件包中diff程序的一个接口。diff有很多选项,但是该
命令最常用的用途是用来生成一个文件,该文件中列出了内容发生改变的行,显示两个原始文
件修改过的行以及由于内容没有变化而忽略掉的行。patch典型地用于把一个目录下的源代码
文件更新到新的版本,从而就避免了下载整个新的源代码档案的必要。下载一个有效的patch
仅仅需要下载发生变化的那些代码行就可以了,这往往是由diff产生的。patch最初源自十几
年前,那时网络带宽的限制促进了patch的发展,然而和当时的很多Unix工具一样,直到现在,
patch还在广泛应用。我想你的toolchain没有理由不包含这个工具吧。
Perl当初只是 Unix 系统管理员的一个工具,被用在无数的小任务中。从那以后,它逐
步发展成为一种全功能的程序设计语言,特别是在各种计算平台上,它被用作 Web 编程、数
据库处理、XML处理以及系统管理 —— 它能够完成所有这些工作,同时仍然是处理小的日常
工作的完美工具,这是它的设计初衷。Perl 快速、有趣,而且特别有用。很多人因为需要
Perl而使用它,又因为热爱它而继续使用它。这样的东西为什么不放在你的toolchain里面呢?
有关Perl的语法等内容超过了本文的范围,请读者参考其他专业著作。
Sed (Stream EDitor)是类UNIX系统上提供将编辑工作自动化的编辑器,使用者无需直接
编辑数据。使用者可利用sed所提供的20多种不同的参数,组合它们完成不同的编辑动作。此
外,由于sed都以行为单位编辑数据,它也是一种行编辑器。一般sed最常用在编辑那些需要不
断重复某些编辑动作的文件上,列入将文件中的某个字符串替换成另外一个字符串等。这些
相对于其他的编辑器(如:vi、emacs等)用手动的方式修改文件,sed用起来较为省力。前
面的内容,有关修改文件内容的操作,我使用的都是sed。
Tar可以为文件和目录创建档案。利用tar,用户可以为某一特定文件创建档案
(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件。tar最初被用来在磁
带上创建档案,现在,用户可以在任何设备上创建档案,如磁盘。利用tar命令,可以把一大
堆的文件和目录全部打包成一个文件,这对于备份文件或将几个文件组合成为一个文件以便于
网络传输是非常有用的。利用tar命令,可以把一大堆的文件和目录全部打包成一个文件,这
对于备份文件或将几个文件组合成为一个文件以便于网络传输是非常有用的。Tar还可以与
bzip2和gzip相结合,创建压缩包,Linux上的大部分软件源代码是用Tar也bzip2或gzip相结合
产生的压缩包形式发布的。Tar产生的文件包文件名以.tar结尾,与bzip2结合产生的包以
.tar.bz2结尾,与gzip结合产生的文件包以.tar.gz结尾。
Util-linux软件包包含许多工具。其中比较重要的是加载、卸载、格式化、分区和管理
硬盘驱动器。你的toolchain需要磁盘挂接和卸载工具,因为在创建基本Linux系统时需要挂接
proc等文件系统。
好了,你需要的大部分软件都介绍完了,最新版本可以在网络上获得,我就不一一列举了。
如果你觉得你的toolchain还需要更多更强的功能,没问题的,下载相应的软件包,创建安装
就行了。当你的toolchain被众多好用强大的软件工具充实之后,可以做的事情不仅仅是为了
创建基本的MagicLinux系统,至于你能将它应用在何种领域或目的,就由读者你细心体会去吧。
2.12 结束语
感谢你能够为了MagicLinux而来阅读这么生涩的文章。本章前部分详细讲述了如何创建一个
gcc环境,因为这非常重要,我不希望你在这个环节有任何失误。
Toolchain技术不仅仅在制作Linux发布时起到很大作用。而且在诸如嵌入式开发等那些需要
交叉环境下应用非常广泛。本章所讨论的内容也不仅限于用于MagicLinux开发的toolchain的制作,
同样适用于其他方面应用的toolchain的制作,不过是给定的一些编译选项有些变化。如果读者
对这方面感兴趣的话,可以据此而举一反三,独立思考一下,并通过互联网寻找你要了解的问
题的答案。
下一章我将让你了解Linux的结构,让你对Linux有一个彻底的了解。
评论
跟着学习
跟着学习