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的制作,不过
是给定的一些编译选项有些变化。如果读者对这方面感兴趣的话,可以据此而举一
反三,独立思考一下,并通过互联网寻找你要了解的问题的答案。如果你想很快的
拥有一个toolchain,而完全自己做感觉吃力的话,你可以参考LFS,它的官方网站
是http://www.linuxfromscratch.org/,那里介绍的内容比文本要全面,而且更为
专业,本文的大部分内容也是参考它的。
下一章我将让你了解Linux的结构,让你对Linux有一个彻底的了解。
(未完,待续...)