linux系统编程专题(二) 手动制作静态库 && 动态库

本文详细介绍了C语言中静态库和动态库的创建过程,包括从源代码编译.o文件,使用ar工具制作静态库,以及使用gcc-shared创建动态库。同时,文章还讨论了动态库在Linux中的加载问题,提供了多种解决加载错误的方法。静态库在编译时将库文件包含进可执行文件,而动态库则在运行时动态加载,两者各有优缺点,如静态库移植方便但占用空间大,动态库节省空间但需要处理运行时依赖。
摘要由CSDN通过智能技术生成

本文主要讲解 静态库 && 动态库的由来、区别,理解它存在的意义,感受C程序设计之美。

一、本文示例代码

新建staticlib文件夹,实现加减乘除c文件。目录结构及源码如下

├── add.c
├── divide.c
├── inc
│   └── head.h
├── minus.c
├── multi.c
└── test.c

程序代码如下:

// test.c
#include "head.h"

int main(int argc, char *argv[])
{
    int a = 10; int b = 5;

    printf("%d+%d=%d\n", a, b, add(a, b));
    printf("%d-%d=%d\n", a, b, minus(a, b));
    printf("%d/%d=%d\n", a, b, divide(a, b));
    printf("%dx%d=%d\n", a, b, multi(a, b));

	return 0;
}

头文件定义

// inc/head.h
#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

int add(int , int );
int minus(int , int );
int divide(int , int );
int multi(int , int );

#endif

加减乘法实现

// add.c
int add(int a, int b)
{
	return a+b;
}
// divide
int divide(int a, int b)
{
	return a/b/2;
}
// minus
int minus(int a, int b)
{
	return a-b;
}
// multi
int multi(int a, int b)
{
	return a*b;
}

二、静态库的制作与使用

2.1、将 .c 生成 .o 文件

gcc -c add.c -o add.o

这里将加减乘除合起来写成一句

gcc -c add.c && gcc -c divide.c && gcc -c minus.c && gcc -c multi.c
image-20220127202810611

2.2、使用 ar 工具制作静态库

ar rcs libmylib.a add.o minus.o multi.o divide.o

注意:静态库名字要以lib 开头,以.a结尾,例如:libmylib.a

运行后,生成libmylib.a静态库文件:

image-20220127202810611

2.3、编译静态库到可执行文件中

这里可执行文件简单取名为a.out

-I:为引入头文件

gcc test.c libmylib.a -o a.out -I./inc

2.4、运行可执行程序

./a.out
image-20220127202810611

三、动态库的制作与使用

新建dynamiclib目录,实例程序还是一样,参考[一、本文示例代码](# 一、本文示例代码)

3.1、生成位置无关的.o文件

-fPIC:使用这个参数过后,生成的函数就和位置无关,挂上@plt标识,等待动态绑定

$ gcc -c add.c -o add.o -fPIC

这里将加减乘除合起来写成一句

gcc -c add.c -fPIC && gcc -c divide.c -fPIC && gcc -c minus.c -fPIC && gcc -c multi.c -fPIC
image-20220127202810611

3.2、使用 gcc -shared制作动态库

理解shared: 动态库又叫做shared动态共享库

gcc -shared -o libmylib.so add.o minus.o multi.o divide.o

生成动态库libmylib.so

image-20220127202810611

我们一般会把动态库放到lib文件夹中

mkdir lib
mv libmylib.so ./lib
image-20220127202810611

3.3、编译动态库到可执行文件中

编译可执行程序时指定所使用的动态库。
-l:指定库名 -L:指定库路径。(注意这里字母是:小l和大l)

gcc test.c -o a.out -l mylib -L ./lib -I./inc
image-20220127202810611

3.4、运行可执行程序

$ ./a.out
image-20220127202810611

3.5、动态库加载错误原因及解决方式

回顾:对于动态库的使用,我们在安卓中会有System.load操作

System.load("mylib");

那么在linux中,我们同样需要分析:

出错原因分析
连接器工作于链接阶段,工作时需要 -l 和 -L
动态链接器工作于程序运行阶段,工作时需要提供动态库所在目录位置

解决方式:

解决方案一:export临时环境变量

注意:只是临时生效, 终端重启环境变量失效

export LD_LIBRARY_PATH=动态库路径

pwd查看当前目录,然后目录指定到lib

export LD_LIBRARY_PATH=/root/gccTest/dynamiclib/lib

可以看到运行成功

image-20220127202810611
解决方案二:环境变量/etc/profile
# 修改环境变量方式1
sudo vim /etc/profile
# 生效命令(也可重启终端)
source /etc/profile
image-20220127202810611

重启终端或者运行source命令后生效

image-20220127202810611
解决方案三:环境变量.bash_profile
# 修改环境变量方式2
sudo vim ~/.bash_profile
# 生效命令(也可重启终端)
source ~/.bash_profile
解决方案四:so库加载路径
sudo vim /etc/ld.so.conf

然后添加上so库文件路径如下

image-20220127202810611

使配置生效

sudo ldconfig -v

然后在运行程序,即可正常使用

./a.out
解决方案五:拷贝so库到系统lib目录

这里的/root/gccTest/dynamiclib/lib/libmylib.so填写你自己的

cp /root/gccTest/dynamiclib/lib/libmylib.so /lib

3.6、查看链接库

ldd是一个脚本,方便查看链接库

ldd a.out
image-20220127202810611

四、 动态库和静态库对比

4.1、静态库特点总结

  • 在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。
  • 静态库对函数库的链接是放在编译时期完成的,程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
image-20220127202810611

4.2、动态库特点总结

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单,甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
image-20220127202810611
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值