zoukankan      html  css  js  c++  java
  • Linux环境下c语言静态链接库和动态链接库创建和使用

    库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。

    面对比一下两者:

        静态链接库:当要使用时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。

    动态库而言:某个程序在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址不无关代码(Position Independent Code (PIC))。

    注意:linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

    一. 静态库

    下面就通过实际的例子来向大家演示一下,该怎样编译和使用静态和动态链接库:

    1. 编辑测试文件

    二个文件:add.c、 sub.c、add.h 、sub.h 和 main.c

    /*.h */

    #ifndef _Time_H_
    #define _Time_H_
    struct Time
    {
        int year;
        int day;    
        int month;
    }time;
    #endif

    每段程序结束这里记得多一空行

    -------------------------------------------------------------------------------------------------

    /*judge.h*/#ifndef _Judge_H_
    #define _Judge_H_
    #include "time.h"
    int judge_is_leap(struct Time *point_time);
    #endif

    -------------------------------------------------------------------------------------------------

    /*panduan*/

    #ifndef _PAN_DUAN_H_
    #define _PAN_DUAN_H_
    #include "time.h"
    int panduan(struct Time *p);
    #endif

    -------------------------------------------------------------------------------------------------

    /*judge.c*/

    #include "judge.h"
    #include "time.h"
    int judge_is_leap(struct Time *p)
    {
        int flag=0;
        if(p->year%4==0&&p->year%100!=0||p->year%100==0&&p->year%400!=0)
        {
            flag=1;
        }
        return flag;
    }

    -------------------------------------------------------------------------------------------------

    /*panduan.c*/

    #include "time.h"
    #include "panduan.h"
    int panduan(struct Time *p)
    {
        int loop=0;
        int Array_month[]={31,28,31,30,31,30,31,31,30,31,30,31};
        
        if(p->day<1||p->day>Array_month[p->month-1])
           loop=1;
        return loop;
    }

    -------------------------------------------------------------------------------------------------

    /*main.c*/

    #include <stdio.h>
    #include "time.h"
    #include "judge.h"
    #include "panduan.h"
    #define Tops point_time->month-1
    int main(void)
    {
        struct Time *point_time;
        int Xunh_num,Sum_day=0,flag=0,flag2;
        point_time=&time;
        int Array_month[]={31,28,31,30,31,30,31,31,30,31,30,31};
        printf("please input year month day ");
        scanf("%d %d %d",&point_time->year,&point_time->month,&point_time->day);
        flag=judge_is_leap(point_time);  
        if(flag==1)
            Array_month[1]++;
        else
            flag=0;
        flag2=panduan(point_time);
        if(flag2==1)
        {
            printf("parameter error");
            return 1;
        }
        for(Xunh_num=0;Xunh_num<Tops;Xunh_num++)
        {
            Sum_day+=Array_month[Xunh_num];
        }
        Sum_day+=point_time->day;
        printf("today is year's %d num ",Sum_day);
        return 0;
    }

    -------------------------------------------------------------------------------------------------

    2. 将 judge.c 和panduan.c 编译生成 .o文件

    gcc -c judge.o

    gcc -c panduan.o

    生成的文件:judge.o,panduan.o

    无论是静态库文件还是动态库文件,都是由 .o 文件创建的。

    3. 由 .o 文件创建静态库(.a 文件)

    ar cr libmymonth.a judge.o panduan.o

    库文件的命名规范是以lib开头(前缀),紧接着是静态库名,以 .a 为后缀名。

    4. 在程序中使用静态库

    gcc -o main main.c -L. -lmymonth

    静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名(mymath 而不是libmymath.a )gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件。在程序3:main.c中,我们包含了静态库的头文件hello.h,然后在主程序main中直接调用公用函数hello。

    5. 下面先生成目标程序main,然后运行main程序看看结果如何。

    ./main

    please input year month day

    2013 8 27

    today is year's 239 num


    二. 动态库

    1. 由 .o 文件创建静态库(.so 文件)

    动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。例如:我们将创建的动态库名为mymath,则动态库文件名就是libmamath.so。用gcc来创建动态库。在系统提示符下键入以下命令得到动态库文件libmamath.so。

    gcc -shared -fPCI -o libmyhello.so hello.o

    2. 在程序中使用动态库

    在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们先运行gcc命令生成目标文件,再运行它看看结果。

    gcc -o main main.c -L. -lmymonth

    ./main

    ./main: error while loading shared libraries:libmymath.so: cannot open shared object file: No such file or directory

    出错了!!!

    快看看错误提示,原来是找不到动态库文件libmyhello.so。程序在运行时,会在/usr/lib/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。

    解决方法:

    我们将文件libmyhello.so复制到目录/usr/lib中:

    mv libmyhello.so /usr/lib/

    运行:

    ./main

    1 + 2 = 3

    1 - 2 = -1

    成功了。这也进一步说明了动态库在程序运行时是需要的。我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?抱着对问题必究到底的心情,来试试看。先删除除.c和.h外的 所有文件,恢复成我们刚刚编辑完举例程序状态。

    gcc -c add.c

    gcc -c sub.c

    ar cr libmymath.asub.o add.o

    gcc -shared -fPCI -o libmyhello.so hello.o

    现在目录有两个同名的库文件(动态库文件和静态库文件同名):

    libmymath.a  libmymath.so

    编译运行程序:

    gcc -o main main.c -L. -lmymath

    ./main

    ./main: error while loading shared libraries:libmymath.so: cannot open shared object file: No such file or directory

    从程序hello运行的结果中很容易知道,当Linux静态库和Linux动态库同名时, gcc命令将优先使用动态库。

  • 相关阅读:
    JAVA中获取路径
    maven 更换阿里镜像、设置本地仓库路径
    Cannot construct instance of `com.jty.entities.Dept` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate or propertybased Creator)
    oracle日期正则表达式
    linux配置jdk
    4月份健身计划
    刚才上了ednchina的blog,发现改版了。竟然登陆不上了
    ②这次将stm32的PC13作为普通i/o口驱动led,不知道能否发生网上提到的现象
    最近画的两块板子。
    RDS的板子推倒重画
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3285534.html
Copyright © 2011-2022 走看看