Linux根文件之lib库制作详解

来源:互联网 发布:python搭建web服务器 编辑:程序博客网 时间:2024/05/17 09:25

20130618

利用交叉编译工具链,构建/lib目录


光有应用程序(命令)是不够的,因为应用程序本身需要使用C库的库函数,因此还必需制作for ARM的C库,并将其放置于/lib目录。还记得交叉编译工具链的3个组成部分吗?交叉编译器、C库和二进制工具

一般的平台C库是现成的,我们只需要拷贝过来就可以了。遗憾的是:整个C库目录下的文件总大小有26M。而我们根文件系统所在分区不过区区16M而已,根本放不下。怎么办呢?

dennis@ desktop: $ du -s --si /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib
26M     /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib

需要C库目录下所有的文件吗?no! 让我们来分析一下glibc库目录下内容的组成该目录下的子目录和文件共分8类

1. 目标文件,如crtn.o,用于gcc链接可执行文件

2. libtool库文件(.la),在链接库文件时这些文件会被用到,比如他们列出了当前库文件所依赖的其它库文件,程序运行时无需这些文件

3. gconv目录,里面是各种链接脚本,在编译应用程序时,他们用于指定程序的运行地址,各段的位置等

4. 静态库文件(.a),例如libm.a,libc.a

5. 动态库文件 (.so、.so.[0-9]*)

6. 动态链接库加载器ld-2.3.6.so、ld-linux.so.2

7. 其它目录及文件

很显然,第1、2、3、4、7类文件和目录是不需要拷贝的。

由于动态链接的应用程序本身并不含有它所调用的C库函数的代码,因此执行时需要动态链接库加载器来为它加载相应的C库文件,所以第6类文件是需要拷贝的。除此之外,第5类文件当然要拷贝。但第5类文件的大小也相当大。

dennis@ desktop: $ du -c --si *.so*

7.2M    total

需要全部拷贝吗?非也,非也!其实,需要哪些库完全取决于要运行的应用程序使用了哪些库函数。如果我们只制作最简单的系统,那么我们只需要运行busybox这一个应用程序即可。通过执行

dennis@ desktop: $ arm-linux-readelf -a bin/busybox | grep 'Shared'
0x00000001 (NEEDED)                     Shared library: [libcrypt.so.1]
0x00000001 (NEEDED)                     Shared library: [libm.so.6]
0x00000001 (NEEDED)                     Shared library: [libc.so.6]

可知:busybox只用到了3个库:通用C库(libc)、数学库(libm)、加密库(libcrypt),因此我们只需要拷贝这3个库的库文件即可。但是每个库都有4个文件,4个文件都要拷贝吗?当然不是。

dennis@ desktop: /gcc-3.4.5-glibc-2.3.6/arm-linux/lib$ ls -l libm[.-]*
-rwxr-xr-x 1 dennis dennis  779096  2008-01-22 05:31      libm-2.3.6.so
-rw-r--r-- 1 dennis dennis 1134282  2008-01-22 05:32      libm.a
lrwxrwxrwx 1 dennis dennis       9    2008-12-22 15:38      libm.so -> libm.so.6
lrwxrwxrwx 1 dennis dennis      13   2008-12-22 15:38      libm.so.6 -> libm-2.3.6.so
4个文件中的.a文件是静态库文件,是不需要拷贝的。另外3个文件是:

· 实际的共享链接库:libLIBRARY_NAME-GLIBC_VERSION.so。当然需要拷贝。

· 主修订版本的符号链接,指向实际的共享链接库:libLIBRARY_NAME.so.MAJOR_REVISION_VERSION,程序一旦链接了特定的链接库,将会参用该符号链接。程序启动时,加载器在加载程序前,会检索该文件。所以需要拷贝。

· 与版本无关的符号链接,指向主修订版本的符号连接libc.so唯一的例外,他是一个链接命令行:libLIBRARY_NAME.so,是为编译程序时提供一个通用条目)。这些文件在程序被编译时会被用到,但在程序运行时不会被用到,所以不必拷贝它。

关于共享库的2个符号链接的作用的特别说明:

当我们使用gcc hello.c -o hello -lm编译程序时,gcc会根据-lm的指示加头(lib)添尾(.so)得到libm.so,从而沿着与版本无关的符号链接(libm.so -> libm.so.6)找到libm.so.6并记录在案hello的ELF头中),表示hello需要使用libm.so.6这个库文件所代表的数学库中的库函数。而当hello被执行的时候动态链接库加载器会从hello的ELF头中找到libm.so.6这个记录,然后沿着主修订版本的符号链接(libm.so.6 -> libm-2.3.6.so)找到实际的共享链接库libm-2.3.6.so,从而将其与hello作动态链接。可见,与版本无关的符号链接是供编译器 使用的,主修订版本的符号链接是供动态链接库加载器使用的,而实际的共享链接库则是供应用程序使用的。

通过以上分析,我们只需要拷贝3个库每个库各1个主修订版本的符号链接和1个实际的共享链接库)以及动态链接库加载器1个符号链接和1个实体文件)。步骤如下:

dennis@ desktop: $ cp  libcrypt-*   /work/nfs_root/fs_mini3/lib

dennis@ desktop: $ cp -l libcrypt.so.*   /work/nfs_root/fs_mini3/lib

dennis@ desktop: $ cp  libm-*   /work/nfs_root/fs_mini3/lib

dennis@ desktop: $ cp -l libm.so.*   /work/nfs_root/fs_mini3/lib

dennis@ desktop: $ cp  libc-*   /work/nfs_root/fs_mini3/lib

dennis@ desktop: $ cp -l libc.so.*   /work/nfs_root/fs_mini3/lib

dennis@ desktop: $ cp -l ld-*   /work/nfs_root/fs_mini3/lib


ldconfig和ldd用法

一、ldconfig命令

ldconfig是一个动态链接库管理命令,为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig。 ldconfig 命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态 链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为 /etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.

linux下的共享库机制采用了类似于高速缓存的机制,将库信息保存在/etc/ld.so.cache里边。

程序连接的时候首先从这个文件里边查找,然后再到ld.so.conf的路径里边去详细找。

这就是为什么修改了ld.so.conf要重新运行一下ldconfig的原因

补充一点,ldconfig在/sbin里面。

ldconfig几个需要注意的地方 :

1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个library会找不到

2. 想往上面两个目录以外加东西的时候,一定要修改/etc/ld.so.conf,然后再调用ldconfig,不然也会找不到比如安装了一个mysql到/usr/local/mysql,mysql有一大堆library在/usr/local/mysql/lib下面,这时 就需要在/etc/ld.so.conf下面加一行/usr/local/mysql/lib,保存过后ldconfig一下,新的library才能在 程序运行时被找到。

3. 如果想在这两个目录以外放lib,但是又不想在/etc/ld.so.conf中加东西(或者是没有权限加东西)。那也可以,就是export一个全局变量LD_LIBRARY_PATH,然后运行程序的时候就会去这个目录中找library。一般来讲这只是一种临时的解决方案,在没有权限或临时需要的时 候使用。(msp700监控器中没有ldconfig命令、没有/etc/ld.so.conf文件,使用加入该LD_LIBRARY_PATH全局变量的方法即可)

4. ldconfig做的这些东西都与运行程序时有关,跟编译时一点关系都没有。编译的时候还是该加-L就得加,不要混淆了。

5. 总之,就是不管做了什么关于library的变动后,最好都ldconfig一下,不然会出现一些意想不到的结果。不会花太多的时间,但是会省很多的事。

二、ldd命令 

作用:用来查看程序运行所需的共享库,常用来解决程序因缺少某个库文件而不能运行的一些问题。

ldd命令原理:

1、首先ldd不是一个可执行程序,而只是一个shell脚本

2、ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量,如下:LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、LD_VERBOSE等。当LD_TRACE_LOADED_OBJECTS环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的dependency,而程序并不真正执行。要不你可以在shell终端测试一下,如下:(1) export LD_TRACE_LOADED_OBJECTS=1;(2) 再执行任何的程序,如ls等,看看程序的运行结果

3、ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld-linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。

4、实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2 --list program(这相当于ldd program)

 


0 0
原创粉丝点击