GCC 中 -L、-rpath和-rpath-link的区别
GCC 中 -L、-rpath和-rpath-link的区别
来源 http://blog.csdn.net/q1302182594/article/details/42102961
关于这3个参数的说明,有不少资料,但是看完了还是觉得模糊,分不清它们的区别。本文将用实验的方法去探讨这3个参数的区别。
1、三个.c文件
1.1 world.c
- #include<stdio.h>
- void world(void) {
- printf("world.\n");
- }
1.2 hello.c
- #include <stdio.h>
- void world(void);
- void hello(void) {
- printf("hello\n");
- world();
- }
1.3 test.c
- void main(void) {
- hello();
- }
2、生成动态库
参照《Linux静态库与动态库制作》,将hello.c和world.c分别生成动态库
- ubuntu $ gcc -c hello.c world.c
- ubuntu $ gcc -shared -o libhello.so hello.o
- ubuntu $ gcc -shared -o libworld.so world.o
这时,生成的文件及其依赖如下图:
由上图可见,libhello.so和libworld都依赖于linux-gate.so.1、libc.so.6以及/lib/ld-linux.so.2,并且这3个库的路径都以及硬编码进libhello.so和libworld.so中了(=>右边的部分)。
然而,虽然libhello.so中调用了libworld.so的函数,但是在上图中并没有显示出此关系。为了达到使libhello.so依赖于libworld.so的目的,在生成libhello.so时要链接到libworld.so:
- ubuntu $ gcc -shared -o libworld.so world.o -lhello -L .
此时,再使用ldd查看libhello.so的依赖:
由上图可见,此时libhello.so已经依赖于libworld.so。
3、编译test.c
3.1 -L
由于test.c直接依赖于libhello.so,因此使用-lhello -L
- ubuntu $ gcc test.c -lhello -L .
结果如下图:
由上图可见已经在-L指定的路径找打了libhello.so,只是libhello.so还需要libworld.so。虽然它都在同一目录下,但是还是没有办法自动找到libworld.so。
那么,能不能使用-lworld将libworld.so也一并链接到test.c中呢?下面做一个尝试:
- ubuntu $ gcc test.c -lhello -lworld -L .
没有报错,成功生成a.out。
执行a.out并且使用ldd查看a.out的依赖:
由上图可见,虽然使用-lworld参数将libworld.so链接到了a.out中,但是上面只显示a.out依赖于libhello.so。由于找不到libhello.so(=> not found)的路径,因此需要设置环境变量LD_LIBRARY_PATH
- ubuntu export LD_LIBRARY_PATH=/home/liyihai/documents
再次执行a.out并使用ldd命令查看a.out的依赖库:
由上图可见,libhello.so已经通过LD_LIBRARY_PATH环境变量找到,并且libworld.so也出现在a.out的依赖中!
结论:-L指定的是链接时的库路径,生成的可执行文件在运行时库的路径由LD_LIBRARY_PATH环境变量指定。
3.2 -rpath
根据3.1第1张图的提示,由于libhello.so依赖于libworld.so,可以只用-rpath或者-rpath-link来指定。这里先使用-rpath。
先清空LD_LIBRARY_PATH环境变量,然后重新编译test.c并且带上-rpath参数:
- ubuntu $ export LD_LIBRARY_PATH=
- ubuntu $ gcc test.c -lhello -L . -Wl,-rpath .
执行a.out,并且使用ldd命令查看a.out的依赖:
由上图可见,虽然没有明确指出链接libworld.so,但是libworld.so还是出现在a.out的依赖中。
另外,虽然LD_LIBRARY_PATH已经清空,但是a.out还是可以执行,这说明库的路径已经被编译进a.out中了。需要注意的是,libhello.so和libworld.so的路径都是通过-rpath指定的路径找到的。
3.2.1 实验1
这时候,如果libhello.so和libworld.so的路径改变了,将会发生什么情况呢?下面做一个实验。
创建一个lib_tmp目录,然后将libhello.so和libworld.so移动进这个目录。
- ubuntu $ mdir lib_tmp
- ubuntu $ mv libhello.so lib_tmp/
- ubuntu $ mv libworld.so lib_tmp/
这时再执行a.out时,提示找不动态库,使用ldd命令查看a.out的库路径:
由上图红色圈部分可见,libhello.so的路径是not found的,并且libworld.so没有出现在其中。这和3.1的情况是相同的。
究其原因,就是要先找到libhello.so再去找libworl.so,因为是libhello.so依赖于libworld.so,而不是a.out依赖于libworld.so。
由此可见,使用了-rpath参数指定库的路径后,生成的可执行文件的依赖库路径并非就固定不变了。而是执行时先从-rpath指定的路径去找依赖库,如果找不到,还是会报not fund。
那么,这时候,LD_LIBRARY_PATH对a.out是否还有影响呢?下面将LD_LIBRARY_PATH设为当前libhello.so和libworld.so所在的路径
- ubuntu $ export LD_LIBRARY_PATH=./lib_tmp
再次执行a.out,并且使用ldd查看此时a.out的依赖库路径:
由上图可见LD_LIBRARY_PATH还是起作用的!由上图可见,和使用-rpath指定路径的效果是一样的。
3.2.2 实验2
将LD_LIBRARY_PATH清空,然后将libhello.so移动到lib_tmp中,而libworld.so则留在documents目录中。
执行a.out,并且使用ldd查看此时a.out的依赖库:
由上图可见,找不到libhello.so。这时,再指定LD_LIBRARY_PATH的路径为libhello.so所在的路径:
- ubuntu $ export LD_LIBRARY_PATH=./lib_tmp/
再次执行a.out,并且使用ldd查看其依赖库:
由上图可见,一切又恢复了正常。此时,libhello.so是通过LD_LIBRARY_PATH找到的,而libworld.so则是通过-rpath指定的路径找到的。
3.2.3 回顾
其实,经过测试,在3.1小节中,如果先指定LD_LIBRARY_PATH的值为libhello.so和libworld.so所在的路径,然后再编译test.c(执行3.1节的第1条编译命令),是可以成功编译的,并不会报3.1小节第1张图的那种错误。也就是说,LD_LIBRARY_PATH不仅指定可执行文件的库路径,还指定了库所依赖于其它库的路径。
3.2.4 结论
并非指定-rpath参数后,就抛弃LD_LIBRARY_PATH环境变量,只是多了个可选的依赖库路径而已。
3.3 -rpath-link
先将LD_LIBRARY_PATH的值清空,然后将libworld.so移动到lib_tmp目录中,而libhello.so则留在documents目录中,使用以下命令对test.c进行编译:
- ubuntu $ gcc test.c -lhello -L . -Wl,-rpath-link ./lib_tmp
执行a.out并且使用ldd查看a.out的依赖库:
找不到 libhello.so,这在预料之中。下面指定LD_LIBRARY_PATH的值为libhello.so的路径,然后在执行a.out,并且查看a.out的依赖:
由上图可见,libhello.so已经通过LD_LIBRARY_PATH找到,但是libworld.so由于没有在LD_LIBRARY_PATH指定的路径中,而且编译时a.out又没有包含库的路径,因此找不到。这
对比3.2.2可以得出结论:-rpath和-rpath-link都可以在链接时指定库的路径;但是运行可执行文件时,-rpath-link指定的路径就不再有效(链接器没有将库的路径包含进可执行文件中),而-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中了。)
最后,不管使用了-rpath还是-rpath-link,LD_LIBRARY_PATH还是有效的。
4、ld命令的man手册
4.1 -rpath=dir
- Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects.
- All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at
- runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly
- included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF
- executable, the contents of the environment variable "LD_RUN_PATH" will be used if it is defined.
- The -rpath option may also be used on SunOS. By default, on SunOS, the linker will form a runtime search path out of
- all the -L options it is given. If a -rpath option is used, the runtime search path will be formed exclusively using
- the -rpath options, ignoring the -L options. This can be useful when using gcc, which adds many -L options which may
- be on NFS mounted file systems.
- For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it
- is treated as the -rpath option.
4.2 -rpath-link=dir
- When using ELF or SunOS, one shared library may require another. This happens when an "ld -shared" link includes a
- shared library as one of the input files.
- When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try
- to locate the required shared library and include it in the link, if it is not included explicitly. In such a case,
- the -rpath-link option specifies the first set of directories to search. The -rpath-link option may specify a sequence
- of directory names either by specifying a list of names separated by colons, or by appearing multiple times.
- This option should be used with caution as it overrides the search path that may have been hard compiled into a shared
- library. In such a case it is possible to use unintentionally a different search path than the runtime linker would do.
4.3 search paths
- The linker uses the following search paths to locate required shared libraries:
- 1. Any directories specified by -rpath-link options.
- 2. Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories
- specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is
- only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers
- which have been configured with the --with-sysroot option.
- 3. On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of
- the environment variable "LD_RUN_PATH".
- 4. On SunOS, if the -rpath option was not used, search any directories specified using -L options.
- 5. For a native linker, search the contents of the environment variable "LD_LIBRARY_PATH".
- 6. For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared
- libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.
- 7. The default directories, normally /lib and /usr/lib.
- 8. For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that
- file.
参考资料
[1]动态库的链接和链接选项-L,-rpath-link,-rpath
GCC 中 -L、-rpath和-rpath-link的区别的更多相关文章
- gcc中动态库和静态库的链接顺序
so文件:动态库a文件: 静态库exe文件:可执行程序(linux下以文件属性来标示是否是可执行文件,与后缀名无关) 经过自己写的一些测试程序,大致了解了下gcc中链接顺序问题,总结出以下几点:1,动 ...
- GNU C/C++ __attributes__ GCC中的弱符号与强符号
最近在看一些源代码,遇到了一些使用__attribute__修饰函数和变量的属性方面的代码,不是太了解,很是汗颜,再此做个总结: GCC使用__attribute__关键字来描述函数,变量和数据类 ...
- gcc中关于静态库和动态库使用(转)
转自:http://blog.chinaunix.net/uid-25871104-id-3069931.html 1,如何生成静态库 静态库只是一堆object对象的集合,使用ar命令可以将.o文件 ...
- gcc中的内嵌汇编语言(Intel i386平台)
[转]http://bbs.chinaunix.net/thread-2149855-1-1.html 一.声明 虽然Linux的核心代码大部分是用C语言编写的,但是不可避免的其中还是有一部分是用汇 ...
- GCC 中零长数组与变长数组
前两天看程序,发现在某个函数中有下面这段程序: int n; //define a variable n int array[n]; //define an array with length n 在 ...
- [转] GCC 中的编译器堆栈保护技术
以堆栈溢出为代表的缓冲区溢出已成为最为普遍的安全漏洞.由此引发的安全问题比比皆是.早在 1988 年,美国康奈尔大学的计算机科学系研究生莫里斯 (Morris) 利用 UNIX fingered 程序 ...
- C++中L和_T()之区别(转)
C++中L和_T()之区别 分类: C/C++2011-01-12 11:45 2878人阅读 评论(1) 收藏 举报 c++编译器apic 字符串前面加L表示该字符串是Unicode字符串._T是一 ...
- GCC 中的编译器堆栈保护技术
GCC 中的编译器堆栈保护技术 前几天看到的觉得不错得博客于是转发了,但这里我补充一下一些点. GCC通过栈保护选项-fstack-protector-all编译时额外添加两个符号,__stack_c ...
- GCC中的内嵌汇编语言
原文可参考:GCC中的内嵌汇编语言 一.声明 虽然Linux的核心代码大部分是用C语言编写的,但是不可避免的其中还是有一部分是用汇编语言写成的.有些汇编语言代码是直接写在汇编源程序中的,特别是Li ...
随机推荐
- map集合修改其中元素 去除Map集合中所有具有相同值的元素 Properties长久保存的流操作 两种用map记录单词或字母个数的方法
package com.swift.lianxi; import java.util.HashMap; import java.util.Iterator; import java.util.Map; ...
- ASP.NET 使用 MySQL
基本是通用的 C#与MySQL的交互, 先添加MySQL.Data.dll(位于MySQL安装目录下的Connector NET 8.0\Assemblies${version}目录下)引用, 之后代 ...
- 【UE4】二十四、UE4内部版本引擎和官方版本引擎版本保持兼容的方法
内部使用的引擎和官方正式发布的引擎版本号不一致,这种情况会导致一些插件由于版本不一致无法使用,有其是在没有插件源码的情况下.解决方法为 修改Engine\Source\Runtime\Launch\R ...
- kafka生产者与消费者的生产消息与消费消息所遇到的问题
当我们用API写kafka的时候 生产者生产消息,但是消费者接收不到消息?集群上启动消费者显示生产的消息.我们需要修改一下配置 (1)我们打开在虚拟机中修改kafka集群的配置文件 [root@spa ...
- oracle(sql)基础篇系列(一)——基础select语句、常用sql函数、组函数、分组函数
花点时间整理下sql基础,温故而知新.文章的demo来自oracle自带的dept,emp,salgrade三张表.解锁scott用户,使用scott用户登录就可以看到自带的表. #使用oracle用 ...
- 剑指Offer - 九度1360 - 乐透之猜数游戏
剑指Offer - 九度1360 - 乐透之猜数游戏2014-02-05 19:54 题目描述: 六一儿童节到了,YZ买了很多丰厚的礼品,准备奖励给JOBDU里辛劳的员工.为了增添一点趣味性,他还准备 ...
- 《Cracking the Coding Interview》——第3章:栈和队列——题目4
2014-03-18 05:28 题目:你肯定听过汉诺威塔的故事:三个柱子和N个从小到大的盘子.既然每次你只能移动放在顶上的盘子,这不就是栈操作吗?所以,请用三个栈来模拟N级汉诺威塔的玩法.放心,N不 ...
- Linux之Permission denied没有权限
在Linux上启动solr时,出现-bash: ./solr: Permission denied的问题. 最简单的解决方式: chmod 777 solr 傻瓜式直接赋予权限
- python-线程进程与队列
线程,有时被称为轻量级进程,是程序执行流的最小单元线程是程序中一个单一的顺序控制流程.进程内一个相对独立的.可调度的执行单元,是系统独立调度和分派CPU的基本单位指进行中的程序的调度单位.在单个程序中 ...
- (原)Skeletal With DirectX12
@author: 白袍小道 @来源: Advanced Animation with DirectX, 游戏引擎架构 (暗影不解释连招) 引言: 3D模型动画的基本原理是让模型 ...