Linux环境下静态库和动态库

1. 库的引入

  c/c++项目的源码文件的组成一般为.c/.cpp和.h文件,可能你写的函数要供其他人使用,但你不能把你写的源码提供给别人,库就很好的解决了这个问题。gcc的-c编译选项可以将c/c++源文件只编译不链接,即生成.o文件。.o文件和.c/.cpp文件实际上都是源代码文件,只是前者是二进制格式的(人眼无法识别其内容),后者是文本格式的(人眼可以识别其内容),对于计算机来说前者后者并无差别,都能正确识别。我们将这些.o文件打包,即可形成一个源码无法被识别的库文件。
  用户无法识别库文件的代码,那如何使用库文件 中的函数?这就需要头文件。因此.h文件是不需要生成二进制格式后提交给用户的,用户根据.h文件中的函数声明就可以正确使用库文件中的函数。

2. 静态库

2.1 命名规则

  Linux环境下静态库的命名由前缀、名称、后缀组成,以libtest.a为例:
  (1)前缀(固定的):lib
  (2)名称(自定义的):test
  (3)后缀(固定的):.a

2.2 静态库的制作

  (1)将.c/.cpp文件生成.o文件

gcc -c a.c b.c

  (2)将.o文件打包
  ar rcs 静态库的名称 .o文件

ar rcs libtest.a a.o b.o

  举例,将用于实现四则运算的.c文件打包成libmycalc.a文件:

//include/calc.h
#ifndef __CALA_H__
#define __CALA_H__

int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);

#endif /* __CALA_H__ */

//src/add.c
#include "calc.h"

int add(int a, int b)
{
    return a + b;   
}

//src/div.c
#include "calc.h"

int div(int a, int b)
{
    return a / b;
}

//src/mul.c
#include "calc.h"

int mul(int a, int b)
{
    return a * b;
}

//src/sub.c
#include "calc.h"

int sub(int a, int b)
{
    return a - b;   
}

这里写图片描述
  (-I指定头文件的路径)

2.3 静态库的使用
//main.c
#include <stdio.h>
#include "calc.h"

int main(void)
{
    printf("%d\n", add(4, 6));  
    return 0;
}

这里写图片描述
  (-L指定库的路径,-l指定库的名称(去除前缀和后缀))

3. 动态库

3.1 命名规则

  Linux环境下动态库的命名依旧由前缀、名称、后缀组成,以libtest.so为例(有的动态库名称还包含版本信息,如libtest.so.10.0.0):
  (1)前缀(固定的):lib
  (2)名称(自定义的):test
  (3)后缀(固定的):.so

3.2 动态库的制作

  (1)将.c/.cpp文件生成.o文件

gcc -c a.c b.c -fpic    //-fpic也可写成-fPIC

  (2)打包

gcc -shared -o libtest.so a.o b.o

  还是以前面的代码为例:
这里写图片描述

3.3 动态库的使用

  跟使用静态库的使用方法一样:
这里写图片描述
  运行a.out时提示找不到libmycalc.so动态库。这是因为:当系统加载可执行代码时,除了需要知道程序所依赖的库的名字,还需要知道该库的绝对路径。前者是通过gcc编译命令选项指定的,后者则是需要系统动态加载器完成。通过ldd命令可查看elf可执行程序所依赖的库:
这里写图片描述
  /lib/ld-linux.so.2即为系统动态加载器。elf格式的可执行程序是由ld-linux.so*来完成的,它先后搜索:

(1)elf文件的DT_RPATH段
(2)环境变量LD_LIBRARY_PATH
(3)/etc/ld.so.cache文件列表
(4)/lib/或/usr/lib目录

  为了让加载器找到动态库,我们可以:
  (1)拷贝自己制作的libmycalc.so到/lib/或/usr/lib中
  (2)临时设置环境变量LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库的路径

  “$LD_LIBRARY_PATH:库的路径”表示在原先的LD_LIBRARY_PATH的值上增加库的路径。
  (3)永久设置环境变量LD_LIBRARY_PATH
  a. 用户级别
  在~/.bashrc文件中增加动态库的搜索的绝对路径
这里写图片描述
  配置完成后需要重启终端或者执行命令:

source ~/.bashrc
或者 .~/.bashrc

  b. 系统级别
  将上述路径增加至/etc/profile,配置完毕后需要重启系统或执行命令:

source /etc/profile
或者 . /etc/profile

  (4)更新/etc/ld.so.cache文件列表
  把动态库的绝对路径添加到配置文件/etc/ld.so.conf中,然后执行命令:

sudo ldconfig -v

4. 两种库的优缺点

4.1 动态库

  需要说明的是:
  a. 动态库并非是在程序启动时就被加载运行内存的,而是在程序使用到动态库的函数时才会被加载进内存。虽然程序启动时若加载器ld-linux-so.2找不到依赖的动态库会报错并停止启动,但这仅仅是加载器预先确定所依赖的动态库的位置。
  b. 以上面用于实现计算的工程为例,libmycalc.so是由add.o、sub.o、mul.o和div.o组成,但是在main()函数中只调用了add()函数,所以加载器加载的仅仅是add.o。
  优点:
  (1)可实现用户进程间的资源共享(不会混乱,每个进程都有独立的地址空间)
  (2)程序员可以控制何时加载动态库(API:dlopen() dlclose() dlsym())
  (3)程序升级简单
  缺点:
  (1)加载速度比静态库慢
  (2)程序发布需要提供依赖动态库

4.2 静态库

  优点:
  (1)静态库被打包到应用程序中加载速度快
  (2)程序发布时无需提供静态库
  缺点:
  (1)浪费内存
  (2)更新、部署、发布麻烦

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值