zoukankan      html  css  js  c++  java
  • 根文件系统的构建与分析(二)之构建动态库

    根文件系统的构建与分析(二)

    转载请注明 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类文件当然要拷贝。 

    [cpp] view plain?
    1. [root@localhost arm-linux]# du -c --si lib/*  

    lib目录一共105M

    [cpp] view plain?
    1. [root@localhost lib]# du -c --si *so*  

    so动态库也有35M

    因此我们要进一步按需定制

    通过arm-linux-readelf命令来找出应用程序依赖于哪些动态链接库

    [cpp] view plain?
    1. [root@localhost my-vod-qt]# arm-linux-readelf -d  my-vod-qt|grep Shared  
    2.  0x00000001 (NEEDED)                     Shared library: [libqte-mt.so.3]  
    3.  0x00000001 (NEEDED)                     Shared library: [libts-0.0.so.0]  
    4.  0x00000001 (NEEDED)                     Shared library: [libstdc++.so.6]  
    5.  0x00000001 (NEEDED)                     Shared library: [libm.so.6]  
    6.  0x00000001 (NEEDED)                     Shared library: [libgcc_s.so.1]  
    7.  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目录下的库文件说明。

    [cpp] view plain?
    1. -rwxr-xr-x 1 root root   226023 2010-05-30 libresolv-2.5.so  
    2. -rw-r--r-- 1 root root   313560 2010-05-30 libresolv.a  
    3. lrwxrwxrwx 1 root root       14 2011-12-15 libresolv.so -> libresolv.so.2  
    4. 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,是为编译程序时提供一个通用条目)。这些文件在程序被编译时会被用到,但在程序运行时不会被用到,所以不必拷贝它。 如:

    [cpp] view plain?
    1. lrwxrwxrwx 1 root root       18 2011-12-15 libXrandr.so -> libXrandr.so.2.1.0  
    [cpp] view plain?
    1. 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 

    [plain] view plain?
    1. for file in libc libcrypt libdl libm libpthread libresolv libutil libthread_db  
    2. do  
    3. cp $file*.so /opt/build_rootfs/lib         #拷贝实际的共享链接库  
    4. cp -d $file.so.* /opt/build_rootfs/lib     #拷贝主修订版本的符号链接  
    5. done  
    6. cp -d ld*.so* /opt/build_rootfs/lib        #拷贝动态连接器及其符合链接  
    7. cp -d libstdc++.so* /opt/build_rootfs/lib  
    8. cp -d libz.so* /opt/build_rootfs/lib  
    9. cp -d libjpeg.so* /opt/build_rootfs/lib  
    10. cp -d libgcc_s* /opt/build_rootfs/lib  

    ps:cp -d或--no-dereference  当复制符号连接时,把目标文件或目录也建立为符号连接,并指向与源文件或目录连接的原始文件或目录。 
    执行source cp.sh后,我们还可以把库的调试符号去掉,从而压缩库的大小

    [cpp] view plain?
    1. arm-linux-strip -s /opt/build_rootfs/lib*  

    再看看lib压缩后的体积

    [cpp] view plain?
    1. [root@localhost build_rootfs]# du -c --si lib/*  

    共6.2M

    [cpp] view plain?
    1. [root@localhost lib]# ls  
    2. ld-2.5.so        libdl-2.5.so       libm.so            libstdc++.so.6  
    3. ld-linux.so.3    libdl.so           libm.so.6          libstdc++.so.6.0.8  
    4. libc-2.5.so      libdl.so.2         libmudflap.so      libthread_db-1.0.so  
    5. libcidn-2.5.so   libgcc_s.so        libmudflapth.so    libthread_db.so  
    6. libcidn.so       libgcc_s.so.1      libpthread-2.5.so  libthread_db.so.1  
    7. libcrypt-2.5.so  libjpeg.so         libpthread.so      libutil-2.5.so  
    8. libcrypto.so     libjpeg.so.62      libpthread.so.0    libutil.so  
    9. libcrypt.so      libjpeg.so.62.0.0  libresolv-2.5.so   libutil.so.1  
    10. libcrypt.so.1    libm-2.5.so        libresolv.so       libz.so  
    11. libc.so          libmemusage.so     libresolv.so.2     libz.so.1  
    12. libc.so.6        libmp3lame.so      libstdc++.so       libz.so.1.2.3  
    13. [root@localhost lib]#   

    至此,一个qt应用程序假如放在根文件系统里,要运行它,它依赖的东西有了,就可以运行了。

  • 相关阅读:
    iOS SQLite函数总结
    转-NSUserDefaults 简介,使用 NSUserDefaults 存储自定义对象
    NSUserDefaults保存用户名和密码
    iOS 集成银联支付(绕过文档的坑,快速集成)-转
    iOS微信支付
    iOS生成PDF的关键代码-备忘
    python中的urlencode和urldecode
    python中%r和%s的区别
    ubuntu16.04安装wps
    二进制、八进制、十进制、十六进制之间的转换
  • 原文地址:https://www.cnblogs.com/alan666/p/8312472.html
Copyright © 2011-2022 走看看