【Linux】动态库/静态库(详解)

目录

动态库/静态库    

概念

例子

生成库

生成动态库

生成静态库

使用库

使用动态库

使用静态库

总结


动态库/静态库    

首先, 我们先来看一下gcc的编译过程

1. 预处理 : 展开所有代码, 所有的宏定义, 所有的条件编译指令, 删除所有注释等

2. 编译 : 代码的语义语法纠错, 完毕之后生成汇编代码

3. 汇编 : 将汇编代码解释成为机器语言

4. 链接 : 将所有的.c文件目标代码链接在一起, 加上所使用的一些库, 生成可执行程序

概念

静态库 (.a) : 程序在编译链接的时候把库的代码链接到可执行文件中, 运行时不再需要

动态库 (.so) : 程序在运行时才链接动态库的代码, 动态库可以在多个程序间共享, 内存中加载一份, 节省磁盘空间, 所以也叫共享库

例子

  我们先来看一个例子

我们在同一个目录下写两个文件

child.c
#include <stdio.h>

void print()
{
    printf("nihao\n");
}
main.c
#include <stdio.h>

int main()
{
    print();
    return 0;
}

我们想要在main.c中使用child.c中的函数print, 我们编译一下

这个时候很明显有一个警告, 显示print函数未定义

所以我们想让一个函数在另一个.c文件中使用我们就要写一个头文件, 将print函数声明一下, 然后将头文件包到两个.c文件中(略)

child.h
#include <stdio.h>
void print();

然后再编译

这样就可以了 

然后我们输入一个命令 : ldd main

 我们可以看到, 有一个libc.so这个库, 这个就是我们的c库, 是一个动态库, 在这里进行了链接, 也就是说我们在生成main这个可执行程

序的时候不仅用到了main.o 和 child.o , 还用到了标准c库, 才生成了可执行程序.

  那么下面我们就来看怎样自己生成库

生成库

这里注意, 库中不能包含main函数, 因为库是给别人去使用的, 别人会自己定义自己的main函数, 要不然会造成重定义

我们就以上面的child.o为例, 生成库

生成动态库

1. gcc -fPIC -c child.c -o child.o


    -fPIC : 产生位置无关代码, 我们一个程序在链接动态库的时候, 这个库中的代码并没有写入到我们的文件中, 所以我们的程

序很难记录库中函数的位置信息, 程序被加载到内存当中时代码都加载在代码端, 但是动态库相当于都是后续加载的, 运行时

才加载,  将动态库加载到内存中, 然后从内存中映射到虚拟地址空间, 映射的地址是不固定的, 所以我们生成动态库的时候就

要产生一个位置无关代码, 这个时候, 产生的代码位置都是相对的, 都是以偏移量计算的, 这时候当动态库加载到内存中, 映射

到虚拟地址空间时, 就会有一个首地址,  我们代码中只记录偏移量时多少, 等到真的从虚拟地址空间拿到首地址后加上偏移量

就可以找到实际的地址.

2. gcc --share child.o -o libmchild.so

    --share : 指定gcc要生成动态库而不是可执行程序

    lib是前缀, .so是后缀, 中间是自己的库名称

可以看到, 我们已经生成了一个动态库

我们来看一下这个动态库.so文件

我们可以看见有很多信息, 我们的print函数也在里面 

生成静态库

1. gcc -c child.c -o child.o

2. ar -cr libmychild.a child.o

    -c : 创建静态库

    -r : 模块替换

    lib是前缀, .a是后缀, 中间是自己的库名称

可以看到, 生成了一个.a文件

然后我们来看一下这个.a文件

可以看到, 里面只有一个child.o文件, 而且只有一个print函数

 

 

使用库

使用动态库

我们编译并且链接库, gcc 默认链接的是动态库, 所以这个地方会连接上动态库

    -l : 指定链接的库名称

报错了, 这是因为链接库的时候, 需要将库放在指定路径下, 搜索库文件的时候是在指定目录下去找的.

一般就是以下几个路径:

/lib
/lib64
/user/lib
/user/lib64

 

解决方案:

1. 将库放到指定目录下----64位操作系统就是 /lib64,  这个简单, 就不用说了, 需要root权限

    运行:

注意 : 运行的时候也需要这个.so文件在这个路径下, 要不然还是会出错

 

2. 设置环境变量-----不会设置的可以看我以前的博客进程概念

(1)库文件的链接搜索路径

(2)库文件的运行加载路径

  运行:

 

3. 在gcc生成可执行程序时直接指定库的搜索路径

    -L : 指定链接库的搜索路径

    .   : 当前路径

这里还有一个选项:

    -I : 指定头文件的搜索路径

如果我们现在新建一个文件夹include, 将child.h放进去, 然后编译, 发现有错误, 找不到child.h

然后我们加上-I , 将child的路径加上, 然后运行, 发现就成功了

 

使用静态库

 有一种写法是gcc  的时候加上-static选项

  但是使用-static的时候, 这个时候c库也就是使用的静态链接, 但是通常我们不想静态链接c库, 因为这样的话会有代码冗余.

我们通常是只想让第三方库使用静态而不是所有的库, 所以我们采用下面的方法

  将第三方静态库拷贝到指定路径下,使用 -L 选项指定库的链接搜索路径,那么这时候,链接的就是静态库.

1. 创建lib文件夹, 将libmchild.a放进去

2. 编译链接时使用-L选项指定搜索静态库搜索路径

  运行 : 这个时候就好了.

所以我们如果要用到第三方静态库, 但是不想静态生成程序, 那么就拷贝静态库然后指定连接路径就好了

 

总结

动态库生成:命名:lib是前缀, .so是后缀,中间是库名称

    gcc -FPIC -c child.c -o child.o

    gcc --share child.o -o libmychild.so

静态库生成:命名:lib是前缀, .a是后缀,中间是库名称

    gcc -c child.c -o child.o

    ar -cr libmychild.a child.o

    -c 创建     -r 模块替换

使用库:链接库的时候,库文件有默认的搜索路径/lib/

    gcc main.c -o main -lmychild 报错:找不着库

    1.将库文件放在指定位置下 /lib64   /lib   /user/lib64   /user/lib

    2.设置环境变量

        库文件的链接搜索路径:LIBRARY_PATH=.

        库文件的运行加载路径:LD_LIBRARY_PATH=.

    3.在gcc升成可执行程序时,直接指定库的搜索路径

        gcc main.c -o main -L . -lmychild

        gcc -L 选项: 指定链接库的搜索路径

        -I 选项: 指定头文件搜索路径

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值