• 动态库和静态库


    前言
           在linux系统下开发应用的时候我们常会用到一些已有的接口,这些接口一般是以库的形式提供给我们使用的,常见的形式有两种,一种以.a为后缀的静态库;一种是以.so为后缀的动态库。

    动态库和静态库的创建和使用
    1.静态库
           假设有一个打印“hello world!”的功能的库,我们要在main函数中调用这个库中的打印接口。下面我们以静态库的形式来实现。
    1.1.创建静态库
           首先,我们有一个打印“hello world!”的源文件
    ydq@docsis4 gcc $ cat hello.c
    #include "hello.h"
    #include <stdio.h>

    void hello(void)
    {
    printf("hello world! ");
    }
    接着我们用这个源文件来生成一个静态库,首先我们必须把源文件hello.c编译为目标文件hello.o。
    ydq@docsis4 gcc $ gcc -c hello.c
    ydq@docsis4 gcc $ ls
    hello.c hello.h hello.o main.c
    然后我们把目标文件归档
    ydq@docsis4 gcc $ ar -r libhello.a hello.o
    ar: creating libhello.a
    ydq@docsis4 gcc $ ls
    hello.c hello.h hello.o libhello.a*

    1.2.链接静态库
           我们用gcc编译时链接静态库,编译完成后,执行以下生成的可执行文件
    ydq@docsis4 gcc $ gcc main.c libhello.a -o main.static
    ydq@docsis4 gcc $ ./main.static
    hello world

    这样,我们就实现了用静态库的方式为我们的程序main.c提供一个打印hello world语言的函数接口了。


    ps: 程序 ar 配合参数 -r 创建一个新库 libhello.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。


    2.动态库
           在这里,我们用动态库的形式实现打印"hello world!"的函数接口。
    2.1.创建动态库
           我们照常用hello.c来编译生成动态库,执行以下命令就可以生成一个动态库。
    ydq@docsis4 gcc $ gcc -fPIC -shared hello.c -o libhello.so
    我们查看一下当前目录,发现多了一个libhello.so文件
    ydq@docsis4 gcc $ ls
    hello.c hello.h libhello.so* main.c

    2.2 动态库的使用
           首先,我们编写一个main.c源文件。
    ydq@docsis4 gcc $ cat main.c
    #include "hello.h"
    #include <stdio.h>

    int main(void)
    {
    hello();
    }
    ydq@docsis4 gcc $
    好了,我们已经有了调用hello()接口的main函数了,这时候可能部分同学就有疑问了,哎我们是怎么知道这个hello()函数是怎么使用的呢?嗯,这个是好问题。一般情况下我们可以通过对应的头文件来查看到这个函数的原型,有了原型,我们就知道咋传参使用啦。下面就是对应的头文件。
    ydq@docsis4 gcc $ cat hello.h
    #ifndef __HELLO_H_
    #define __HELLO_H_

    extern void hello(void);

    #endif
    好的,现在我们已经知道怎么使用hello()函数和编写了一个调用hello函数的main.c源文件,接下来我们就来编译可执行文件啦,编译很简单,我们只需要在gcc编译时加上-lhello选项就可以链接上动态库了,好让我们来尝试一下。
    ydq@docsis4 gcc $ gcc main.c -o main -lhello
    /usr/bin/ld: cannot find -lhello
    collect2: error: ld returned 1 exit status
    我去,咋回事?怎么提示说不能够找到hello这个库?莫非命令敲错了?其实没有指定动态库的路径拉,一般情况下系统只认/usr/lib这个目录是动态库的目录,所以编译器在链接的时候会默认去/usr/lib目录上找,在/usr/lib目录里当然没有你的libhello.so库啦。听到我这样说,肯定有很多小机灵鬼知道咋解决了,我直接把libhello.so给拷贝到/usr/lib目录下不就行了吗?嗯,这个确实可以解决问题,不过,我们还可以加-L./来指定链接的时候在当前工作目录下寻找libhello.so。好,我们再试一下。
    ydq@docsis4 gcc $ gcc main.c -o main -lhello -L./
    编译成功了,这时候我们在当前目录下有了main这个可执行文件,好家伙,让我们执行试试。
    ydq@docsis4 gcc $ ./main
    ./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
    哦,这个是咋回事?执行的时候又找不到这个动态库了?怎么解决呢?莫非也可以把libhello.so拷贝到/usr/lib上去就可以解决了?答案是不行的拉,除非是在链接前就把libhello.so放到/usr/lib目录中,这样在main执行的时候,才不会提示说找不到该库。那有没有解决方法呢?肯定啦,不然还怎么玩。

    这时候,我们需要利用一个叫环境变量的东西(在这里就不讲了,自行google或百度啦),我们可以通过export,把当前目录添加到环境变量中去,查找动态库的环境变量名是LD_LIBRARY_PATH。接下来我们执行看看
    ydq@docsis4 gcc $ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
    执行完毕后,我们运行main试试。
    ydq@docsis4 gcc $ ./main
    hello world
    oh,喜大普奔,我们终于可以执行main可执行文件,也终于可以调用hello打印函数打印出hello world!了。

    总结

    到了这里,我们已经讲明白了动态库和静态库的创建和使用过程,下一章节我们会讲动态库和静态库的区别,以及选择使用静态库还是使用动态库的理由。

  • 相关阅读:
    codesmith+mysql生成代码
    遭遇笔试
    线性是一种简洁,简洁就是美
    Microsoft Kinect SDK vs PrimeSense OpenNI
    资料收集:让OpenCV使用IPP
    提纲
    在PC上安装使用Kinect
    OpenNI设置Kinect帧率,读取IR图
    cout,rather than printf
    单步调试时,getnextframe会失败。又
  • 原文地址:https://www.cnblogs.com/ydqblogs/p/13329088.html
Copyright © 2020-2023  润新知