编译和链接通过生成可执行文件,但运行时找不到动态库
2013-12-23 18:35
946 查看
编译和链接通过生成可执行文件balreport, 但运行时却出现如下的错误:
[wzheng88@bevertec bin]$ balreport -d provident
balreport: error while loading shared libraries: libhpdf-2.1.0.so: cannot open shared object file: No such file or directory
[wzheng88@bevertec bin]$
[wzheng88@bevertec bin]$ which libhpdf-2.1.0.so
/usr/bin/libhpdf-2.1.0.so
动态库文件存在,但程序运行时找不到这个动态库,使用ldd命令:
[wzheng88@bevertec bin]$ ldd balreport
libhpdf-2.1.0.so =>not found
libpng12.so.0 => /usr/lib/libpng12.so.0 (0x00879000)
libclntsh.so.10.1 => /usr/lib/oracle/10.2.0.3/client/lib/libclntsh.so.10.1 (0x03584000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00d13000)
libm.so.6 => /lib/tls/libm.so.6 (0x00b14000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00d07000)
libc.so.6 => /lib/tls/libc.so.6 (0x009dc000)
libz.so.1 => /usr/lib/libz.so.1 (0x00c3e000)
libnnz10.so => /usr/lib/oracle/10.2.0.3/client/lib/libnnz10.so (0x0024a000)
libdl.so.2 => /lib/libdl.so.2 (0x00b0e000)
libpthread.so.0 => /lib/tls/libpthread.so.0 (0x00c1a000)
libnsl.so.1 => /lib/libnsl.so.1 (0x00231000)
/lib/ld-linux.so.2 (0x009c2000)
解决方案:
1. 执行程序前,配一下库的搜索路径:
export LD_LIBRARY_PATH=/usr/local/lib/
2.检查一下/etc/ld.so.conf/里的conf文件,看是否包含/usr/local/lib
有点话,直接?sudo ldconfig更新系统;没有的话讲该路径加入,然后再更新。
我用第一种方法能够找到库了,但运行时还是原来的错误,我觉得是我的权限不够吧。
网上找到的一些资料:
首先回答前面的问题,一共有多少种方法来指定告诉linux共享库链接器ld.so已经编译好的库libbase.so的位置呢?答案是一共有五种,它们都可以通知ld.so去哪些地方找下已经编译好的c语言函数动态库,它们是:
1)ELF可执行文件中动态段中DT_RPATH所指定的路径。即在编译目标代码时, 对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径,eg:gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c
2)环境变量LD_LIBRARY_PATH 指定的动态库搜索路径
3)/etc/ld.so.cache中所缓存的动态库路径,这个可以通过先修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令来改变。
4)默认的动态库搜索路径/lib
5)默认的动态库搜索路径/usr/lib
另外:在嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库,3在嵌入式系统中使用的比较少, 因为有很多系统根本就不支持ld.so.cache。
那么,动态链接器ld.so在这五种路径中,是按照什么样的顺序来搜索需要的动态共享库呢?答案这里先告知就是按照上面的顺序来得,即优先级是:1-->2-->3-->4-->5。我们可以写简单的程序来证明这个结论。
首先,写成5个函数,这5个函数名称都叫pt,但是里面的内容不一样:
pt1.c
#include <stdio.h>
void pt(){
printf("1 path on the gcc give \n");
}
pt2.c
#include <stdio.h>
void pt(){
printf("2 path on the LD_LIBRARY_PATH \n");
}
pt3.c
#include <stdio.h>
void pt(){
printf("3 path on the /etc/ld.so.conf \n");
}
pt4.c
#include <stdio.h>
void pt(){
printf("4 path on the /lib \n");
}
pt5.c
#include <stdio.h>
void pt(){
printf("5 path on the /usr/lib \n");
}
然后,分别编译这5个函数,然后将它们分别移到上面5种情况对应的5个不同目录下:
gcc -fPIC -c pt1.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/1/
gcc -fPIC -c pt2.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/2/
gcc -fPIC -c pt3.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/3/
gcc -fPIC -c pt4.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /lib/
gcc -fPIC -c pt5.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /usr/lib/
再次,编写一个main函数m,让它来调用函数pt:
m.c
#include <stdio.h>
int main(){
printf("start....\n");
pt();
printf("......end\n");
return 0;
}
最后,准备环境,让ld都知道这5个路径:
(a) 往/etc/ld.so.conf总增加一行,内容:/tmp/st/3,然后执行 ldconfig 命令
(b) export LD_LIBRARY_PATH=/tmp/st/2
另外3中路径,ld都可以得到,请接着看下面。
之后测试:
gcc m.c -o m1 -L/tmp/st/1 -lpt -Wl,-rpath,/tmp/st/1
./m1
start....
1 path on the gcc give
......end
这里在可执行文件中动态段中DT_RPATH所指定的路径,因此需要在编译m.c的时候就指定路径,由于其他路径都也告诉了ld,很明显,此种方法优先级最高了。
gcc m.c -o m -L/tmp/st/1 -lpt
./m
start....
2 path on the LD_LIBRARY_PATH
......end
这里很显然调用了LD_LIBRARY_PATH指定了路径中的共享库,因此此种情况优先级第二。
mv /tmp/st/2/libpt.so /tmp/st/2/libpt2.so
/m
start....
3 path on the /etc/ld.so.conf
......end
这里是调用了/etc/ld.so.cache中所缓存的动态库路径中的共享库,因此此种情况优先级第三。
mv /tmp/st/3/libpt.so /tmp/st/3/libpt3.so
./m
start....
4 path on the /lib
......end
这里是调用/lib中的共享库,优先级第四。
rm /lib/libpt.so
./m
start....
5 path on the /usr/lib
......end
这里是调用/lib中的共享库,优先级第五。
http://blog.sina.com.cn/s/blog_690c46500100kxhd.html
另一个的链接:
http://www.360doc.com/content/12/0313/10/8093902_193931244.shtml
故证明这五种路径指定方法的优先级是1-->2-->3-->4-->5!
[wzheng88@bevertec bin]$ balreport -d provident
balreport: error while loading shared libraries: libhpdf-2.1.0.so: cannot open shared object file: No such file or directory
[wzheng88@bevertec bin]$
[wzheng88@bevertec bin]$ which libhpdf-2.1.0.so
/usr/bin/libhpdf-2.1.0.so
动态库文件存在,但程序运行时找不到这个动态库,使用ldd命令:
[wzheng88@bevertec bin]$ ldd balreport
libhpdf-2.1.0.so =>not found
libpng12.so.0 => /usr/lib/libpng12.so.0 (0x00879000)
libclntsh.so.10.1 => /usr/lib/oracle/10.2.0.3/client/lib/libclntsh.so.10.1 (0x03584000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00d13000)
libm.so.6 => /lib/tls/libm.so.6 (0x00b14000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00d07000)
libc.so.6 => /lib/tls/libc.so.6 (0x009dc000)
libz.so.1 => /usr/lib/libz.so.1 (0x00c3e000)
libnnz10.so => /usr/lib/oracle/10.2.0.3/client/lib/libnnz10.so (0x0024a000)
libdl.so.2 => /lib/libdl.so.2 (0x00b0e000)
libpthread.so.0 => /lib/tls/libpthread.so.0 (0x00c1a000)
libnsl.so.1 => /lib/libnsl.so.1 (0x00231000)
/lib/ld-linux.so.2 (0x009c2000)
解决方案:
1. 执行程序前,配一下库的搜索路径:
export LD_LIBRARY_PATH=/usr/local/lib/
2.检查一下/etc/ld.so.conf/里的conf文件,看是否包含/usr/local/lib
有点话,直接?sudo ldconfig更新系统;没有的话讲该路径加入,然后再更新。
我用第一种方法能够找到库了,但运行时还是原来的错误,我觉得是我的权限不够吧。
网上找到的一些资料:
首先回答前面的问题,一共有多少种方法来指定告诉linux共享库链接器ld.so已经编译好的库libbase.so的位置呢?答案是一共有五种,它们都可以通知ld.so去哪些地方找下已经编译好的c语言函数动态库,它们是:
1)ELF可执行文件中动态段中DT_RPATH所指定的路径。即在编译目标代码时, 对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径,eg:gcc -Wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c
2)环境变量LD_LIBRARY_PATH 指定的动态库搜索路径
3)/etc/ld.so.cache中所缓存的动态库路径,这个可以通过先修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令来改变。
4)默认的动态库搜索路径/lib
5)默认的动态库搜索路径/usr/lib
另外:在嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库,3在嵌入式系统中使用的比较少, 因为有很多系统根本就不支持ld.so.cache。
那么,动态链接器ld.so在这五种路径中,是按照什么样的顺序来搜索需要的动态共享库呢?答案这里先告知就是按照上面的顺序来得,即优先级是:1-->2-->3-->4-->5。我们可以写简单的程序来证明这个结论。
首先,写成5个函数,这5个函数名称都叫pt,但是里面的内容不一样:
pt1.c
#include <stdio.h>
void pt(){
printf("1 path on the gcc give \n");
}
pt2.c
#include <stdio.h>
void pt(){
printf("2 path on the LD_LIBRARY_PATH \n");
}
pt3.c
#include <stdio.h>
void pt(){
printf("3 path on the /etc/ld.so.conf \n");
}
pt4.c
#include <stdio.h>
void pt(){
printf("4 path on the /lib \n");
}
pt5.c
#include <stdio.h>
void pt(){
printf("5 path on the /usr/lib \n");
}
然后,分别编译这5个函数,然后将它们分别移到上面5种情况对应的5个不同目录下:
gcc -fPIC -c pt1.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/1/
gcc -fPIC -c pt2.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/2/
gcc -fPIC -c pt3.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/3/
gcc -fPIC -c pt4.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /lib/
gcc -fPIC -c pt5.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /usr/lib/
再次,编写一个main函数m,让它来调用函数pt:
m.c
#include <stdio.h>
int main(){
printf("start....\n");
pt();
printf("......end\n");
return 0;
}
最后,准备环境,让ld都知道这5个路径:
(a) 往/etc/ld.so.conf总增加一行,内容:/tmp/st/3,然后执行 ldconfig 命令
(b) export LD_LIBRARY_PATH=/tmp/st/2
另外3中路径,ld都可以得到,请接着看下面。
之后测试:
gcc m.c -o m1 -L/tmp/st/1 -lpt -Wl,-rpath,/tmp/st/1
./m1
start....
1 path on the gcc give
......end
这里在可执行文件中动态段中DT_RPATH所指定的路径,因此需要在编译m.c的时候就指定路径,由于其他路径都也告诉了ld,很明显,此种方法优先级最高了。
gcc m.c -o m -L/tmp/st/1 -lpt
./m
start....
2 path on the LD_LIBRARY_PATH
......end
这里很显然调用了LD_LIBRARY_PATH指定了路径中的共享库,因此此种情况优先级第二。
mv /tmp/st/2/libpt.so /tmp/st/2/libpt2.so
/m
start....
3 path on the /etc/ld.so.conf
......end
这里是调用了/etc/ld.so.cache中所缓存的动态库路径中的共享库,因此此种情况优先级第三。
mv /tmp/st/3/libpt.so /tmp/st/3/libpt3.so
./m
start....
4 path on the /lib
......end
这里是调用/lib中的共享库,优先级第四。
rm /lib/libpt.so
./m
start....
5 path on the /usr/lib
......end
这里是调用/lib中的共享库,优先级第五。
http://blog.sina.com.cn/s/blog_690c46500100kxhd.html
另一个的链接:
http://www.360doc.com/content/12/0313/10/8093902_193931244.shtml
故证明这五种路径指定方法的优先级是1-->2-->3-->4-->5!
相关文章推荐
- c/c++ 编译链接通过,运行时却报找不到.so文件
- #LINUX#通过编译链接,却运行时找不到.so文件
- Ubuntu安装CodeBlocks相关问题(不能编译或者编译通过但不能生成可执行文件)
- 1.预处理,生成预编译文件(.文件): Gcc –E hello.c –o hello.i 2.编译,生成汇编代码(.s文件): Gcc –S hello.i –o hello.s 3.汇编,生成目标文件(.o文件): Gcc –c hello.s –o hello.o 4.链接,生成可执行文件: linux笔记
- ubuntu用qt creator写的程序编译后生成的可执行文件复制到另一个系统中需要哪些文件才能运行
- 一个简单的 C 程序文件,经过 0、编写,1、预处理,2、编译,3、链接,终于生成了一个可执行文件
- ROS中编译通过但是遇到可执行文件找不到的问题
- winserver2008,运行可执行文件,提示 激活上下文生成失败。 找不到从属程序集 Microsoft.VC90.DebugCRT,processorArchitecture="x86"
- VC编译\链接\运行:包含文件、包含库lib、包含动态库dll的一些问题
- 在Ubuntu下用ndk-build编译一个链接opencv库的cpp文件生成一个在安卓机上跑的执行文件
- keil5 编译的时候不通过找不到sys.o文件,运行不通过解决方法(win10)
- 建立工程后刚开始编译出现了“error PRJ0003 : 生成 cmd.exe 时出错”这样的错误,虽然在debug中生成了.exe文件,但是无法执行,提示找不到mfc90ud.dll。
- 解决:Android编译源码根目录下/system/vold后,通过push命令将编译生成的vold文件push至system/bin下无法正常开机
- VS2010 编译 sqlite3 生成动态库和链接库
- 分析源代码编译链接过程和shell中ELF格式可执行文件的初始化执行过程
- g++ 编译链接C++代码, 生成与使用静态库和动态库
- GCC编译链接到生成可执行
- 如何在OS X Lion下编译FFmpeg生成可执行文件
- javac编译成功,用java运行class文件出现“找不到或无法加载主类” 的问题解决起来很简单
- 在windows上编译chez scheme代码生成独立可执行文件