gcc使用---动态库链接静态库

最近自己的项目中遇到一个问题:

编译一个动态库,动态库中使用了静态库的函数如下图所述

问题来了怎么编译最终得到一个带有静态链接的动态库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使用的时候带有参数,这些参数的先后顺序直接导致了编译的结果。特别是在做库文件的过程中,有时候看似编译没有报错,但是运行时候就会有问题。这些问题多数出现在链接阶段。


文中有不足之处请大家指点,谢谢


展开阅读全文

没有更多推荐了,返回首页