今天在Linux下使用Protobuf时,编译成功后,运行时出现这种错误:“error while loading shared libraries: libprotobuf.so.7: cannot open shared object file: No such file or directory”。于是花时间弄清楚原因,找到解决方案,跟大家共享一下。
源文件如下:
testSo1.h
#ifndef _TEST1
#define _TEST1
void print1();
#endif
testSo1.cpp
#include <stdio.h>
#include "testSo1.h"
void print1()
{
printf("fenngwang love jocelyn!\n");
return ;
}
testSo2.h
#ifndef _TEST2
#define _TEST2
void print2();
#endif
testSo2.cpp
#include <stdio.h>
#include "testSo2.h"
void print2()
{
printf("jocelyn love fenngwang!\n");
return ;
}
main.cpp
#include "testSo1.h"
#include "testSo2.h"
int main()
{
print1();
print2();
return 0;
}
一、生成静态库
1. 编译文件
g++ -c testSo1.cpp 生成testSo1.o
g++ -c testSo2.cpp 生成testSo2.o
2.打包为库文件
ar参数意义:
r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。
s:写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。
v:该选项用来显示执行操作选项的附加信息。
t:显示库的模块表清单。一般只显示模块名。
ar -rsv libtestSo.a testSo1.o testSo2.o
3. 编译main.cpp,链接生成可执行程序
g++ -o main main.cpp -L./ -ltestSo
4. 执行
[wangfeng@localhost program]$ ./main
fenngwang love jocelyn!
jocelyn love fenngwang!
5. 编译完成后每个文件的大小
二、生成动态库
1. 编译源文件
g++ -c -fPIC testSo1.cpp
g++ -c -fPIC testSo2.cpp
此处编译参数 -fPIC 一定不能省略,否则下一步将会失败;因为g++默认生成的.o文件是不带-fPIC选项,即生成的是静态链接文件,故下一步封装 生成动态库时会失败。
2. 生成共享库so文件
g++ -shared -o libtestSo.so testSo1.o testSo2.o
3. 生成可执行程序
g++ -o main main.cpp -L./ -ltestSo
4. 文件的大小
奇怪,为什么这里的main的大小和静态库生成的main的大小一样呢?
5. 执行main函数
错误提示:error while loading shared libraries: libtestSo.so: cannot open shared object file: No such file or directory
原因:使用动态库的函数,在执行时才会加载库文件,系统查找库文件根据以下规则
运行时使用非标准位置/usr/lib和/lib下的库的方式有三种:
(1) 设置$LD_LIBRARY_PATH=库所在目录(多个目录用:分隔),系统加载工具ld.so/ld-linux.so将顺序搜索变量指定的目录。例如
#$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf2.4.1/lib
(2) 以root身份把库路径加入/etc/ld.so.conf或在/etc/ld.so.conf.d中创建特定的.conf文件,然后运行ldconfig更新/etc/ld.so.cache。例如: 在/etc/ld.so.conf.d下创建文件mysql.conf写入/usr/local/mysql/lib
(3) 另一种办法就是把需要的库copy到/usr/lib或/lib,但这不是建议的方法,特别是尽量避免copy发到/lib。但这种方法可以在编译时免去用-L选项。
共享库搜索顺序一般是$LDLIBRARY_PATH,/etc/ld.so.cache, /usr/lib, /lib
6. 添加路径,执行./main
三、编译参数解析
-shared: 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。当于一个可执行文件;
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的
-L.: 表示要连接的库在当前目录中 ;
-libcacl.a/so: 编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称;
四、优先级
若同一个目录下既有静态库.a,又有动态库.so,则编译链接时优先使用动态库,可通过如下方法验证。
(1) 先把cacl.h test_cacl.C这两个文件都拷贝到libtest目录下,然后将目录a中的libcacl.a和目录so中的libcacl.so拷贝到libtest目录下,使用命令“g++ -o testcacl test_cacl.C -L. -lcacl”编译链接生成可执行程序testcacl;
(2) 运行testcacl,运行结果正确;
(3) 删除libcacl.so之后,运行testcacl,会报错“testcacl: error while loading shared libraries: libcacl.so: cannot open shared object file: No such file or directory”。