根文件系统的构建与分析(二)
转载请注明 http://blog.csdn.net/jianchi88 Author:Lotte 邮箱:baihaowen08@126.com
我们依旧记得系统启动流程:硬件上电--》bootloader--》Linux内核--》挂载根文件系统--》应用程序
上一篇,我们建好了根文件系统的目录。这篇的任务是
利用交叉编译工具链,构建动态库
qt应用程序依赖一些动态库文件才能运行,如qt库,c库。因为应用程序本身需要使用C库的库函数,因此还必需制作for ARM的C库,并将其放置于/lib目录。还记得交叉编译工具链的3个组成部分吗?交叉编译器、for ARM的C库和二进制工具。for ARM的C库是现成的,我们只需要拷贝过来就可以了。遗憾的是:整个C库目录下的文件总大小有26M。而我们根文件系统所在分区不过区区16M而已,根本放不下。怎么办呢?我们只需要拷贝有用的。
交叉应用程序的开发需要用到交叉编译的链接库,交叉编译的链接库是在交叉工具链的lib目录下,我们在移植应用程序到我们的目标板的时候,需要把交叉编译的链接库也一起移植到目标板上,这里我用到的交叉工具链的路径是/opt/4.1.2/,所以链接库的目录是/opt/4.1.2/arm-linux/lib,此lib目录有下面这些东西:
- 目标文件,如crtn.o,用于gcc链接可执行文件
- libtool库文件(.la),在链接库文件时这些文件会被用到,比如他们列出了当前库文件所依赖的其它库文件,程序运行时无需这些文件
- gconv目录,里面是各种链接脚本,在编译应用程序时,他们用于指定程序的运行地址,各段的位置等 (我的4.1.2没有这个目录)
- 静态库文件(.a),例如libm.a,libc.a
- 动态库文件 (.so、.so.[0-9]*)
- 动态链接库加载器ld-2.3.6.so、ld-linux.so.2
- 其它目录及文件
很显然,第1、2、3、4、7类文件和目录是不需要拷贝的。
由于动态链接的应用程序本身并不含有它所调用的C库函数的代码,因此执行时需要动态链接库加载器来为它加载相应的C库文件,所以第6类文件是需要拷贝的。第5类文件当然要拷贝。
[root@localhost arm-linux]# du -c --si lib/*
lib目录一共105M
[root@localhost lib]# du -c --si *so*
so动态库也有35M
因此我们要进一步按需定制
通过arm-linux-readelf命令来找出应用程序依赖于哪些动态链接库
[root@localhost my-vod-qt]# arm-linux-readelf -d my-vod-qt|grep Shared
0x00000001 (NEEDED) Shared library: [libqte-mt.so.3]
0x00000001 (NEEDED) Shared library: [libts-0.0.so.0]
0x00000001 (NEEDED) Shared library: [libstdc++.so.6]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.6]
my-vod-qt是一个qt应用程序,可见它依赖的库。
libqte-mt.so.3 是qte库
libts-0.0.so.0 是ts库
libstdc++.so.6 是C++库
libm.so.6 是数学库
libgcc_s.so.1 是gcc编译相关的库
libc.so.6 是C库
下面找一个/opt/4.1.2/arm-linux/lib目录下的库文件说明。
-rwxr-xr-x 1 root root 226023 2010-05-30 libresolv-2.5.so
-rw-r--r-- 1 root root 313560 2010-05-30 libresolv.a
lrwxrwxrwx 1 root root 14 2011-12-15 libresolv.so -> libresolv.so.2
lrwxrwxrwx 1 root root 16 2011-12-15 libresolv.so.2 -> libresolv-2.5.so
假如我们要用到libresolv这个动态库,我们需要拷贝哪些?
首先libresolv.a、xxx.la肯定不用的。上文已经提及过。
实际的共享链接库的格式是libLIBRARY_NAME-GLIBC_VERSION.so 这个需要拷贝,如libresolv-2.5.so
主修订版本的符号链接,指向实际的共享链接库:libLIBRARY_NAME.so.MAJOR_REVISION_VERSION,程序一旦链接了特定的链接库,将会参用该符号链接。程序启动时,加载器在加载程序前,会检索该文件。所以需要拷贝。 如:libresolv.so.2
另外,与版本无关的符号链接,指向主修订版本的符号连接(libc.so是唯一的例外,他是一个链接命令行:libLIBRARY_NAME.so,是为编译程序时提供一个通用条目)。这些文件在程序被编译时会被用到,但在程序运行时不会被用到,所以不必拷贝它。 如:
lrwxrwxrwx 1 root root 18 2011-12-15 libXrandr.so -> libXrandr.so.2.1.0
lrwxrwxrwx 1 root root 14 2011-12-15 libresolv.so -> libresolv.so.2
通过上面分析,我们只需要拷贝实际的共享链接库、主修订版本的符号链接和动态链接库加载器。
下面我们假设/opt/build_rootfs目录是要制作的根文件系统。并编写一个shell脚本用于copy实际的共享链接库、主修订版本的符合链接、动态连接器加载器及其符号链接到目标板根目录下的lib(/opt/build_rootfs/lib),拷贝这些库能适用大部分qt应用程序,而不仅仅是我的my-vod-qt。
vi cp.sh
for file in libc libcrypt libdl libm libpthread libresolv libutil libthread_db
do
cp $file*.so /opt/build_rootfs/lib #拷贝实际的共享链接库
cp -d $file.so.* /opt/build_rootfs/lib #拷贝主修订版本的符号链接
done
cp -d ld*.so* /opt/build_rootfs/lib #拷贝动态连接器及其符合链接
cp -d libstdc++.so* /opt/build_rootfs/lib
cp -d libz.so* /opt/build_rootfs/lib
cp -d libjpeg.so* /opt/build_rootfs/lib
cp -d libgcc_s* /opt/build_rootfs/lib
ps:cp -d或--no-dereference 当复制符号连接时,把目标文件或目录也建立为符号连接,并指向与源文件或目录连接的原始文件或目录。
执行source cp.sh后,我们还可以把库的调试符号去掉,从而压缩库的大小
arm-linux-strip -s /opt/build_rootfs/lib*
再看看lib压缩后的体积
[root@localhost build_rootfs]# du -c --si lib/*
共6.2M
[root@localhost lib]# ls
ld-2.5.so libdl-2.5.so libm.so libstdc++.so.6
ld-linux.so.3 libdl.so libm.so.6 libstdc++.so.6.0.8
libc-2.5.so libdl.so.2 libmudflap.so libthread_db-1.0.so
libcidn-2.5.so libgcc_s.so libmudflapth.so libthread_db.so
libcidn.so libgcc_s.so.1 libpthread-2.5.so libthread_db.so.1
libcrypt-2.5.so libjpeg.so libpthread.so libutil-2.5.so
libcrypto.so libjpeg.so.62 libpthread.so.0 libutil.so
libcrypt.so libjpeg.so.62.0.0 libresolv-2.5.so libutil.so.1
libcrypt.so.1 libm-2.5.so libresolv.so libz.so
libc.so libmemusage.so libresolv.so.2 libz.so.1
libc.so.6 libmp3lame.so libstdc++.so libz.so.1.2.3
[root@localhost lib]#
至此,一个qt应用程序假如放在根文件系统里,要运行它,它依赖的东西有了,就可以运行了。