源文章地址:https://blog.csdn.net/edwardlulinux/article/details/56812636
最近自己的项目中遇到一个问题:
编译一个动态库,动态库中使用了静态库的函数如下图所述
问题来了怎么编译最终得到一个带有静态链接的动态库libxxx.so?
生成静态库libxxx1
gcc -o xxx1.o -c xxx1.c
ar -r xxx1.o libxxx1.a
生成静态库libxxx2
gcc -o xxx2.o -c xxx2.c
ar -r xxx2.o libxxx2.a
生成静态库libxxx3
gcc -o xxx3.o -c xxx3.c
ar -r xxx3.o libxxx3.a
生成动态库libxxx.so
gcc -o libdynamic.so dynamic.o -shared -fPIC -L. -lxxx1 -lxxx2 -lxxx3
gcc报错:
ibxxx.a xxx.o:relocation against '.rodata' can not be used when making a shared object;recomplie with -fPIC
于是网上看了一篇文章解决方案是把静态库编译的过程加上了-fPIC和-shared选项。然后进行编译和链接再生成动态库被程序所使用。最为关键的一些变化为:回到以上静态库生成指令中
gcc -o xxx1.o -fPIC -shared -c xxx1.c
gcc -o xxx2.o -fPIC -shared -c xxx2.c
gcc -o xxx3.o -fPIC -shared -c xxx3.c
这样一来不禁要问:既然是静态库,加上了这两选项编译出来的结果到底是动态库还是静态库?那原本的问题岂不是变为动态库链接动态库了?
之后结合个人调试和总结看看有没有其他方法可以解决此类问题(动态库调用静态库中的函数)
1,静态库被其他程序调用,编译结果为把静态库的函数“拷贝”到目标程序中。
2,而动态库这没有相关的“拷贝”动作。只是做了一个链接,程序运行时会自动的到默认路径下搜索动态库,并且调用执行。
明确以上两个概念之后再来看看实际的情况
代码转自:
http://www.cnblogs.com/nobugtodebug/archive/2012/11/07/e6cd72c67b3dd843f40d7ce919f7336a.html
#include
const char* sz_static = "i'm a static str.";
void print_niuzai_said()
{
printf("in static lib, niu zai said, i'm happy!\n");
}
#include
#include "static.h"
void print_papa_said()
{
print_niuzai_said();
printf("in dynamic lib, papa said, niu zai is wonderful!\n");
}
#include
#include "dynamic.h"
int main(int argc, char** argv)
{
print_papa_said();
return 0;
}
emptyempty
以上代码中很清楚的可以看到如下实时。生成一个动态库,这个动态库依中的函数实现依赖于一个静态库。满足要分析的应用场景。那么为什么按照博客中描述的方法操作gcc,但是结果和我预期的有出入呢?
问题在于两点:
第一点:使用 -fPIC -shared 两个选项编译了静态库,这个库还是静态属性吗?假设一个静态库已经被其他软件和工程广泛使用了,现在修改了这个静态库属性后是不是会影响其他的软件?
第二点:为什么不能编译出我们预期效果的动态库?
看看博客中的操作:
gcc -o static.o -c static.c
ar -r libstatic.a static.o
gcc -o dynamic.o -c dynamic.c
做个静态库libstatic.a,然后只编译dynamic.c不链接。
接着使用
gcc -o libdynamic.so -shared -fPIC -L. -lstatic dynamic.o
生成一个名为libdynamic.so动态库。
一切准备就绪,要用测试软件测试了
gcc main.c -L. -ldynamic -o main
./libdynamic.so: undefined reference to `print_niuzai_said' collect2: ld returned 1 exit status
链接错误
我们分析一下原因:
使用命令 nm 查看可执行程序的符号和函数等
nm libdynamic.so
00001f18 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_w _Jv_RegisterClasses
00001f08 d __CTOR_END__
00001f04 d __CTOR_LIST__
00001f10 d __DTOR_END__
00001f0c d __DTOR_LIST__
00000558 r __FRAME_END__
00001f14 d __JCR_END__
00001f14 d __JCR_LIST__
0000200c A __bss_start w __cxa_finalize@@GLIBC_2.1.3
000004d0 t __do_global_ctors_aux
000003f0 t __do_global_dtors_aux
00002008 d __dso_handle w __gmon_start__
000004a7 t __i686.get_pc_thunk.bx
0000200c A _edata
00002014 A _end
00000508 T _fini
00000388 T _init
0000200c b completed.7021
00002010 b dtor_idx.7023
00000470 t frame_dummy
U print_niuzai_said
000004ac T print_papa_said
U puts@@GLIBC_2.0
这个U 后面的函数正是静态库中想要使用的函数,前面这个U 表示:该符号在当前文件中是未定义的,即该符号的定义在别的文件中。
看来这个动态库名字是对的,但是内容还不全。怎么办?修改gcc命令如下:
gcc -o libdynamic1.so -shared -fPIC dynamic.o -L. -lstatic
这条命令是告诉gcc先要把dynamic.o这个编译后未链接的文件中没有定义的符号链接先处理掉,也就是把U开始的函数先链接。随后再把这个未连接的文件作为动态库来处理,最后生成一个动态库。
有了动态库libdynamic1.so,再使用nm看看输出结果:
00001f18 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_w _Jv_RegisterClasses
00001f08 d __CTOR_END__
00001f04 d __CTOR_LIST__
00001f10 d __DTOR_END__
00001f0c d __DTOR_LIST__
000005e4 r __FRAME_END__
00001f14 d __JCR_END__
00001f14 d __JCR_LIST__
00002010 A __bss_start w __cxa_finalize@@GLIBC_2.1.3
00000520 t __do_global_ctors_aux
00000430 t __do_global_dtors_aux
00002008 d __dso_handle w __gmon_start__
000004e7 t __i686.get_pc_thunk.bx
00002010 A _edata
00002018 A _end
00000558 T _fini
000003c8 T _init
00002010 b completed.7021
00002014 b dtor_idx.7023
000004b0 t frame_dummy
00000508 T print_niuzai_said
000004ec T print_papa_said
U puts@@GLIBC_2.0
0000200c D sz_static
这下这个函数变为 属性变为T了,T的含义是:该符号位于代码区text section。
使用命令:gcc main.c -L. -ldynamic1 -o main
执行main后一切都有了,静态库中的函数信息最后是动态库中的信息。
总结:
gcc使用的时候带有参数,这些参数的先后顺序直接导致了编译的结果。特别是在做库文件的过程中,有时候看似编译没有报错,但是运行时候就会有问题。这些问题多数出现在链接阶段。
文中有不足之处请大家指点,谢谢
---------------------
作者:小陆zi
来源:CSDN
原文:https://blog.csdn.net/edwardlulinux/article/details/56812636
版权声明:本文为博主原创文章,转载请附上博文链接!