Linux动静态库

本文围绕Linux系统中的库展开,介绍了库的概念、类型,包括开源库、闭源库(静态库和动态库)。详细阐述了库的组成文件,以及静态库和动态库的实现过程,如建立文件、交付、编译器作用等。还说明了OS找到动态库的方法,最后对比了动静态库的加载情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、库的概念与类型

二、库的组成文件(.o)

2.1 初始源代码(.c .h)

2.2 可重定位二进制文件(.o) 

2.3 库文件(lib) 与 头文件(.h)

三、实现静态库(.a)

3.1 建立静态库文件

3.2 交付库

3.3 编译器在编译链接中的作用

3.4 使用第三方静态库与头文件

3.4.2 只指定头文件路径(×)

3.4.3 指定头路径与库文件路径(×)

3.4.4 指定头文件路径和库文件名称(√)

3.5 C编译器默认动态链接

3.6 安装第三方静态库与头文件

四、实现简单的动态库

4.1 动态库建立打包

4.2 动态链接需要给OS提供库的路径

4.3 OS找到动态库方法

4.3.1 环境变量法(临时法)

4.3.2 配置文件法

4.3.3 建立软链接(或者直接添加到系统默认路径下)

五、动静态库加载理解

5.1 静态库加载理解

5.2 动态库加载理解 


一、库的概念与类型

(百度)

库是程序代码的集合,是共享程序代码的一种方式。根据源代码的公开情况,库可以分为两种类型:

1. 开源库,公开源代码,能看到具体实现,比如:SDWebImage、AFNetworking。

2. 闭源库不公开源代码,是经过编译后的二进制文件看不到具体实现。闭源库主要分为:静态库和动态库。

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

动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码

二、库的组成文件(.o)

2.1 初始源代码(.c .h)

//add.h 
#pragma
#include<stdio.h>

extern int add(int a ,int b);

//sub.h
#pragma
#include<stdio.h>
extern int sub(int a,int b);


//sub.c
#include"add.h"

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

//add.c
#include"sub.h"

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

//main.c
#include"add.h"
#include"sub.h"

int main()
{
    int a=9,b=1;
    printf("%d+%d=%d\n",a,b,add(a,b));
    printf("%d-%d=%d\n",a,b,sub(a,b));
    return 0;
}

2.2 可重定位二进制文件(.o) 

 这种文件将我们.c源代码变成了二进制文件,它依然可以链接形成exe文件,但是它们本身是二进制文件,所以没有暴漏了原来.c的源代码!我们可以将这些.o文件打包Output,用户拿着这些文件链接形成exe文件!


2.3 库文件(lib) 与 头文件(.h)

将我们.o文件集合打包成一个文件,这种文件我们称为库文件(lib)!

系统默认头文件路径 /usr/include/
默认库文件路径 /usr/lib64/

交付库--》将.a/.so 文件以及其对应的.h文件交给用户!

三、实现静态库(.a)

3.1 建立静态库文件

//makefile

//静态库.a
libmymath.a:add.o sub.o
	ar -rc $@ $^    //ar -rc 打包.o文件-》静态库(.a)
add.o:add.c
	gcc -c $^ -o $@
sub.o:sub.c
	gcc -c $^ -o $@
.PHONY:clean
clean:
	rm -f *.o

3.2 交付库

3.2.1 发布库

libmymath.a:add.o sub.o
	ar -rc $@ $^		
add.o:add.c
	gcc -c $^ -o $@
sub.o:sub.c
	gcc -c $^ -o $@

//发布
.PHONY:output
output:
	mkdir -p mylib/include    //当前路径下建立头文件目录
	mkdir -p mylib/lib       //当前路径下建立库文件目录
	cp *.h   mylib/include   //头文件打包
	cp *.a   mylib/lib       //库文件打包

.PHONY:clean
clean:
	rm -f *.o

3.2.2 用户下载库


  3.3 编译器在编译链接中的作用

编译器会在编译链接中查找库与头文件!

系统库与头文件下:

编译器如何寻找头文件?

我们在写代码的时候包含头文件,编译器会拿着这些头文件名称到系统指定路径(/usr/include/)路径下寻找!

编译器如何寻找库文件?

同样,编译器会到指定路径去寻找库!用户没有直接提供库名称,但是编译器会知道找哪些库!

编译器默认链接方式:动态库链接!

3.4 使用第三方静态库与头文件

3.4.1 单纯使用gcc -o (×)


3.4.2 只指定头文件路径(×)


3.4.3 指定头路径与库文件路径(×)


 3.4.4 指定头文件路径和库文件名称(√)

库的名称是去掉前缀(lib)和后缀的(.a/.so)剩下的!


3.5 C编译器默认动态链接


一个程序可以链接很多库文件,如果既可以链接动态库又可以链接动态库,则编译器默认选择链接动态库!除非只有一种库形式存在,否则链接方式由编译器决定!


3.6 安装第三方静态库与头文件

将第三方库文件与头文件拷贝至我们的对应的系统默认路径下:

系统默认头文件路径 /usr/include/
默认库文件路径 /usr/lib64/

这样我们就可以不带路径找到头与库文件,但是我们必须还要指定链接的库文件名称!


四、实现简单的动态库

4.1 动态库建立打包


4.2 动态链接需要给OS提供库的路径

 同样的操作,动态链接这样依旧不能运行!发现我们依旧打不开库文件!编译链接可以成功但是运行不行!编译链接时编译器的工作,我们把路径和库文件名告诉了编译器,所以可以编译链接成功!但是运行归OS管,OS找不到第三方库!OS只会在系统默认库路径下或者当前路径下查找!所以我们必须将我们的库文件安装到默认路径下!

4.3 OS找到动态库方法

4.3.1 环境变量法(临时法)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库文件路径!

4.3.2 配置文件法

cd /etc/ld.so.conf.d/ 系统目录,查看配置文件

创建.conf类型的目录并将动态库路径添加到这个目录下! 
sudo ldconfig 更新缓存刷新一下

4.3.3 建立软链接(或者直接添加到系统默认路径下)

OS只会在系统默认库路径下或者当前路径下查找,所以我们可以:

1.在当前路径下建立库文件的软链接

2.在系统库路径下添加库文件的软链接



五、动静态库加载理解

5.1 静态库加载理解

静态链接是将静态库代码拷贝到进程的代码区,这些代码在代码区被编址!这样相当于这部分拷贝代码本身就属于我们这个进程!


5.2 动态库加载理解 


动态库链接,当我们进程代码用到了外部库函数调用/变量,OS会将其对应的动态库加载到内存中,虚拟地址空间共享区与之映射! 

外部库加载到内存后,进程如何准确找到外部库对应的函数?

进程中的外部库函数代码本身存载了自己在库中的地址偏移量!通过相对共享区起始位置的偏移量在共享区中找到自己的虚拟地址,然后映射到物理内存中找到我们函数的定义!

5.3 两者对比


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值