o: 编译的目标文件
a: 静态库,其实就是把若干o文件打了个包
so: 动态链接库(共享库)

lo: 使用libtool编译出的目标文件,其实就是在o文件中添加了一些信息
la: 使用libtool编译出的库文件,其实是个文本文件,记录同名动态库和静态库的相关信息
 
1 libtool的工作原理 
libtool 是一个通用库支持脚本,将使用动态库的复杂性隐藏在统一、可移植的接口中;使用libtool的标准方法,可以在不同平台上创建并调用动态库。可以认为libtool是gcc的一个抽象,其包装了gcc(或者其他的编译器),用户无需知道细节,只要告诉libtool需要编译哪些库即可,libtool将处理库的依赖等细节。libtool只与后缀名为lo、la为的libtool文件打交道。

libtool主要的一个作用是在编译大型软件的过程中解决了库的依赖问题;将繁重的库依赖关系的维护工作承担下来,从而释放了程序员的人力资源。libtool提供统一的接口,隐藏了不同平台间库的名称的差异等细节,生成一个抽象的后缀名为la高层库libxx.la(其实是个文本文件),并将该库对其它库的依赖关系,都写在该la的文件中。该文件中的dependency_libs记录该库依赖的所有库(其中有些是以.la文件的形式加入的);libdir则指出了库的安装位置;library_names记录了共享库的名字;old_library记录了静态库的名字。

当编译过程到link阶段的时候,如果有下面的命令:

$libtool --mode=link gcc -o myprog -rpath /usr/lib –L/usr/lib –la

libtool会到/usr/lib路径下去寻找liba.la,然后从中读取实际的共享库的名字(library_names中记录了该名字,比如liba.so)和路径(lib_dir中记录了,比如libdir=’/usr/lib’),返回诸如/usr/lib/liba.so的参数给激发出的gcc命令行。

如果liba.so依赖于库/usr/lib/libb.so,则在liba.la中将会有dependency_libs=’-L/usr/lib -lb’或者dependency_libs=’/usr/lib/libb.la’的行,如果是前者,其将直接把“-L/usr/lib –lb”当作参数传给gcc命令行;如果是后者,libtool将从/usr/lib/libb.la中读取实际的libb.so的库名称和路径,然后组合成参数“/usr/lib/libb.so”传递给gcc命令行。

当要生成的文件是诸如libmylib.la的时候,比如:

$libtool --mode=link gcc -o libmylib.la -rpath /usr/lib –L/usr/lib –la

其依赖的库的搜索基本类似,只是在这个时候会根据相应的规则生成相应的共享库和静态库。

注意:libtool在链接的时候只会涉及到后缀名为la的libtool文件;实际的库文件名称和库安装路径以及依赖关系是从该文件中读取的。

2 为何使用 -Wl,--rpath-link -Wl,DIR?
使用libtool解决编译问题看上去没什么问题:库的名称、路径、依赖都得到了很好的解决。但下结论不要那么着急,一个显而易见的问题就是:并不是所有的库都是用libtool编译的。

比如上面那个例子,

$libtool --mode=link gcc -o myprog -rpath /usr/lib –L/usr/lib –la

如果liba.so不是使用libtool工具生成的,则libtool此时根本找不到liba.la文件(不存在该文件)。这种情况下,libtool只会把“–L/usr/lib –la”当作参数传递给gcc命令行。

考虑以下情况:要从myprog.o文件编译生成myprog,其依赖于库liba.so(使用libtool生成),liba.so又依赖于libb.so(libb.so的生成不使用libtool),而且由于某种原因,a对b的依赖并没有写入到liba.la中,那么如果用以下命令编译:

$libtool --mode=link gcc -o myprog -rpath /usr/lib –L/usr/lib –la

激发出的gcc命令行类似于下面:

gcc –o myprog /usr/lib/liba.so

由于liba.so依赖于libb.so(这种依赖可以用readelf读liba.so的ELF文件看到),而上面的命令行中,并没有出现libb.so,于是,可能会出现问题。

说“可能”,是因为如果在本地编译的情况下,gcc在命令行中找不到一个库(比如上面的liba.so)依赖的其它库(比如libb.so),链接器会按照某种策略到某些路径下面去寻找需要的共享库:

1. 所有由'-rpath-link'选项指定的搜索路径.

2. 所有由'-rpath'指定的搜索路径. '-rpath'跟'-rpath_link'的不同之处在于,由'-rpath'指定的路径被包含在可执行文件中,并在运行时使用, 而'-rpath-link'选项仅仅在连接时起作用.

3. 在一个ELF系统中, 如果'-rpath'和'rpath-link'选项没有被使用, 会搜索环境变量'LD_RUN_PATH'的内容.它也只对本地连接器起作用.

4. 在SunOS上, '-rpath'选项不使用, 只搜索所有由'-L'指定的目录.

5. 对于一个本地连接器,环境变量'LD_LIBRARY_PATH'的内容被搜索.

6. 对于一个本地ELF连接器,共享库中的`DT_RUNPATH'和`DT_RPATH'操作符会被需要它的共享库搜索. 如果'DT_RUNPATH'存在了, 那'DT_RPATH'就会被忽略.

7. 缺省目录, 常规的,如'/lib'和'/usr/lib'.

8. 对于ELF系统上的本地连接器, 如果文件'/etc/ld.so.conf'存在, 这个文件中有的目录会被搜索.

从以上可以看出,在使用本地工具链进行本地编译情况下,只要库存在于某个位置,gcc总能通过如上策略找到需要的共享库。但在交叉编译下,上述八种策略,可以使用的仅仅有两个:-rpath-link,-rpath。这两个选项在上述八种策略当中优先级最高,当指定这两个选项时,如果链接需要的共享库找不到,链接器会优先到这两个选项指定的路径下去搜索需要的共享库。通过上面的描述可以看到:-rpath指定的路径将被写到可执行文件中;-rpath-link则不会;我们当然不希望交叉编译情况下使用的路径信息被写进最终的可执行文件,所以我们选择使用选项-rpath-link。

gcc的选项“-Wl,--rpath-link –Wl,DIR”会把-rpath-link选项及路径信息传递给链接器。回到上面那个例子,如果命令行中没有出现libb.so,但gcc指定了“-Wl,--rpath-link –Wl,DIR”,则链接器找不到libb.so的时候,会首先到后面-rpath-link指定的路径去寻找其依赖的库。此处我们使用的编译命令的示例是使用unicore平台的工具链。

$ unicore32-Linux-gcc –o myprog /usr/lib/liba.so \

-Wl,--rpath-link -Wl,/home/UNITY_float/install/usr/lib

这样,编译器会首先到“/home/UNITY_float/install/usr/lib”下面去搜索libb.so

libtool如何把选项“-Wl,--rpath-link –Wl,DIR”传递给gcc?libtool中有一个变量“hardcode_libdir_flag_spec”,该变量本来是传递“-rpath”选项的,但我们可以修改它,添加我们需要的路径,传递给unicore32-linux-gcc。

“hardcode_libdir_flag_spec”原来的定义如下:

hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir"

我们修改后的定义如下:

hardcode_libdir_flag_spec="\${wl}—rpath-link \${wl}\$libdir \

-Wl,--rpath-link -Wl,/home/UNITY_float/install/usr/lib \

-Wl,--rpath-link -Wl,/home/UNITY_float/install/usr/X11R6/lib "

这样,当libtool在“--mode=link”的模式下,就会把选项“-Wl,--rpath-link –Wl,DIR”传递给gcc编译器

linux下的so、o、lo、a、la文件的区别的更多相关文章

  1. (转)yi_meng linux 下 ifcfg-eth0 配置 以及ifconfig、ifup、ifdown区别

    linux 下 ifcfg-eth0 配置 以及ifconfig.ifup.ifdown区别 原文:https://www.cnblogs.com/yi-meng/p/3214471.html这3个命 ...

  2. 将linux下的rm命令改造成移动文件至回收站【转】

    转自:http://blog.csdn.net/a3470194/article/details/16863803 [-] 将linux下的rm命令改造成移动文件至回收站 将AIX下的rm命令改造成移 ...

  3. Linux下fork()、vfork()、clone()和exec()的区别

    转自Linux下fork().vfork().clone()和exec()的区别 前三个和最后一个是两个类型.前三个主要是Linux用来创建新的进程(线程)而设计的,exec()系列函数则是用来用指定 ...

  4. linux下怎么删除名称带空格的文件

    linux下怎么删除名称带空格的文件-rm 'mysql bin.000005' 用引号把文件名括起来 某些情况下会出现名称带空格的文件, 如果想要删除的话,直接用rm mysql bin.00000 ...

  5. linux下常用FTP命令 上传下载文件【转】

    1. 连接ftp服务器 格式:ftp [hostname| ip-address]a)在linux命令行下输入: ftp 192.168.1.1 b)服务器询问你用户名和密码,分别输入用户名和相应密码 ...

  6. Linux下hosts、host.conf、resolv.conf的区别

    /etc/resolv.conf 该文件是DNS域名解析的配置文件,它的格式很简单,每行以一个关键字开头,后接配置参数.resolv.conf的关键字主要有四个,分别是:nameserver   #定 ...

  7. (转)Linux下/etc/rc.local与/etc/init.d的区别与联系

    Linux下/etc/rc.local与/etc/init.d的区别与联系 2012-10-13 20:14:52|  分类: Linux学习|字号 订阅     1./etc/rc.local 这是 ...

  8. Linux下 解包/打包 Android 映像文件 system.img, boot.img, ramdisk.img, userdata.img.

    Linux下 解包/打包 Android 映像文件 system.img, boot.img, ramdisk.img, userdata.img. 2014年10月20日 ⁄ 计算机视觉 ⁄ 共 1 ...

  9. 将linux下的rm命令改造成移动文件至回收站

    将linux下的rm命令改造成移动文件至回收站 rm是Linux下文件删除的命令,它是Linux下非常强大却又非常危险的一条命令,特别是rm -rf有时候强大到让你欲哭无泪,当你想清除当前目录下的所有 ...

  10. LINUX学习笔记——LINUX下EXP命令全库备份数据库文件

    LINUX下EXP命令全库备份数据库文件 1)建立备份目录,目录操作权限授权给Oracle用户 mkdir /backup  --创建backup文件夹 cd  /   --进入cd语句 ls  -l ...

随机推荐

  1. Apache添加到windows服务和移除Apache的windows服务

    Apache添加到windows服务和移除Apache的windows服务 Apache免安装版将其添加到Windows服务中: 打开cmd控制台,在上面输入"你的Apache安装目录\bi ...

  2. 00Enterprise Resource Planning

    Enterprise Resource Planning         企业资源计划即 ERP (Enterprise Resource Planning),由美国 Gartner Group 公司 ...

  3. CSDN怎么转载别人的博客

    在参考"如何快速转载CSDN中的博客"后,由于自己不懂html以及markdown相关知识,所以花了一些时间来弄明白怎么转载博客,以下为转载CSDN博客步骤和一些知识小笔记. 参考 ...

  4. UVA - 12589 Learning Vector(dp-01背包)

    题目: 思路: dp[j][h]表示选取了j个向量,且高度为h,利用01背包来解决问题. 没选当前的向量:dp[j][h] = dp[j][h]; 选了当前的向量:dp[j][h] = dp[j-1] ...

  5. MySQL异常:com.mysql.jdbc.PacketTooBigException: Packet for query is too large

    ### Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1169 > 1024). You ...

  6. mysql的密码管理、mysql初始密码查找、密码修改、mysql登录

    1.查询mysql的初始密码: 初始密码密码是随机产生的,每台机器产生的都不一样的 grep 'temporary password' /var/log/mysqld.log 或者 cat /var/ ...

  7. change legend layout from 'vertical' to 'horizontal' in Paraview

    ********** # get color legend/bar for 'vLUT' in view 'renderView1'vLUTColorBar = GetScalarBar(vLUT, ...

  8. HDU - 6446 Tree and Permutation

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6446 本题是一个树上的问题——DFS. 一棵N个结点的树,其结点为1~N.树具有N-1条边,每一条边具有 ...

  9. ZOJ 3684 Destroy

    Destroy Time Limit: 2000ms Memory Limit: 65536KB This problem will be judged on ZJU. Original ID: 36 ...

  10. Poor Hanamichi

    Poor Hanamichi Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...