动态库和静态库

动态链接和静态链接

c/c++源文件要经过预处理、编译、汇编、链接才能形成可执行程序.

在c/c++中,以c语言标准库为例:.h头文件一般存放方法的声明,而方法的实现会放在库中.

其中链接分为两种:

静态链接:将库中方法的具体实现,拷贝到我们的可执行程序中,此时程序的运行不需要依赖库,但是体积会变大.

动态链接:将库的地址,拷贝到我们的可执行程序中,程序运行要依赖动态库,程序运行时,需要到动态库里去找函数的实现.

gcc/g++默认是动态链接,如果要静态链接,加上选项-static

静态链接的文件大小远远大于动态链接的文件

ldd可以查看可执行程序链接的动态库

linux: .so(动态库) .a(静态库)

windows: .dll(动态库) .lib(静态库)

制作静态库

静态库的本质:把所有.o文件打包,就是形成静态库

test1.h

test1.c

test2.h

test2.c

ar -rc lib库名.a 要打包的全部.o文件

ar ------ 归档 全称archive

r ------ 替换

c ------ 创建

lib自定义库名.a ------ 前缀lib固定,.a是静态库的后缀

例如:makefile自动化构建静态库,libstatic.a就是生成的静态库,打包了test1.o和test2.o的代码

makefile 复制代码
libstatic.a:test1.o test2.o    
    ar -rc libstatic.a test1.o test2.o    
test1.o:test1.c    
    gcc -c test1.c -o test1.o   
test2.o:test2.c    
    gcc -c test2.c -o test2.o    
.PHONY:clean    
clean:    
    rm -f libstatic.a test1.o test2.o   

一般而言,发布一个写好的库,需要包含头文件(方法列表)和库文件(方法实现),目录结构如下:

优化后的makefile如下:

makefile 复制代码
libstatic.a:test1.o test2.o    
    ar -rc libstatic.a test1.o test2.o    
test1.o:test1.c    
    gcc -c test1.c -o test1.o    
test2.o:test2.c    
    gcc -c test2.c -o test2.o    
    
.PHONY:static    
static:    
    mkdir -p static/include    
    mkdir -p static/lib    
    cp test1.h test2.h static/include     
    cp libstatic.a static/lib    #生成库的目录结构                                                                                                                                                                
.PHONY:clean    
clean:    
    rm -rf static libstatic.a test1.o test2.o    

如何使用静态库

一、将库的头文件和库文件拷贝到系统路径下

将库的头文件和库文件,拷贝到系统路径下,就是库的安装

对于gcc/g++,头文件的默认搜索路径是:/usr/include

库文件的默认搜索路径是:/lib64 或/usr/lib64

拷贝完成效果

main.c要使用static库的方法

arduino 复制代码
//main.c
#include <test1.h>    
#include <test2.h>    
int main()    
{
    //都是static库的方法
    test1();
    test2();                   
    return 0;    
}    

static是第三方库,尽管已经被拷贝进系统路径,也必须手动让gcc/g++链接

gcc main.c -o main -lstatic

二、直接链接第三方库,不拷贝到系统路径下

gcc main.c -I ./static/include -L ./static/lib -lstatic

-I:头文件搜索路径

-L:库文件搜索路径

-l:在指定路径下,指定使用库名

制作动态库

gcc -fPIC -c test1.c -o test1.o # 形成与位置无关的目标二进制文件

gcc -shared .o文件列表 -o lib动态库名.so

1 理解:与位置有关

静态库形成后,静态库的代码最后是要放进可执行程序内部

可执行程序有自己的地址空间,静态库要链接进来,

静态库的代码和数据的地址,必须在地址空间的特定位置,已经固定.

代码和常量在代码区、局部变量在栈区等

例如:main是静态链接static后形成的可执行程序,

objdump -t main 可以查看程序的符号表.

objdump -t main | grep 'test'

2 理解:与位置无关

动态库将来采用相对地址的方案

链接动态库后,生成可执行程序

只有当进程执行,要访问动态库的方法时,此时才将动态库的代码加载进内存,和当前进程的地址空间通过页表建立映射关系,将动态库的代码映射到 共享区,此时才会确定方法的地址.

如果有很多个进程,动态库只要加载一次,就能被多个进程共同使用,同一份动态库代码,通过页表可以被映射到多个进程地址空间的共享区.

例如:下面的main和上面的不一样,是动态链接生成的可执行程序

3 优化makefile,同时生成动静态库

makefile 复制代码
.PHONY:all    
all:libstatic.a libdynamic.so    
    
libdynamic.so:test1dynamic.o test2dynamic.o    
    gcc -shared test1dynamic.o test2dynamic.o -o libdynamic.so    
test1dynamic.o:test1.c    
    gcc -fPIC -c test1.c -o test1dynamic.o    
test2dynamic.o:test2.c    
    gcc -fPIC -c test2.c -o test2dynamic.o    
libstatic.a:test1.o test2.o    
    ar -rc libstatic.a test1.o test2.o    
test1.o:test1.c    
    gcc -c test1.c -o test1.o    
test2.o:test2.c    
    gcc -c test2.c -o test2.o    
    
.PHONY:Lib    
Lib:    
    mkdir -p Lib/include    
    mkdir -p Lib/lib    
    cp test1.h test2.h Lib/include     
    cp libstatic.a libdynamic.so Lib/lib    
.PHONY:clean    
clean:    
    rm -rf Lib libstatic.a test1.o test2.o libdynamic.so test1dynamic.o test2dynamic.o 

如何使用动态库

一、 将动态库拷贝到系统路径中

gcc默认链接动态库

1 如果只有静态库,gcc只能针对该库进行静态链接

2 如果动静态库同时存在,默认用动态库

-static:摒弃默认使用动态库的原则,而是直接使用静态库的方案

二、直接链接动态库

为什么ldd 可执行程序,仍然找不到动态库?

因为运行加载时,和gcc已经没有关系了,链接时只告诉了gcc库的地址,现在应该要告诉 os的加载器 动态库的地址 (如果把库的文件放到系统路径中,是可以直接运行的)

1 设置系统环境变量 LD_LIBRARY_PATH

加载时,库的搜索路径都被放在该环境变量中

可以将动态库所在路径放进该环境变量中

(重新登录后,会在系统配置文件中重新拿LD_LIBRARY_PATH的值,之前设置的环境变量会被重置)

2 修改配置文件,/etc/ld.so.conf.d

在该路径下创建一个文件xxx.conf,用vim打开后,把库路径拷贝进去

ldconfig 让配置文件生效

即使LD_LIBRARY_PATH里没有这个库路径,但仍能正常运行

3 建立软链接

ln -s ./Lib/lib/libdynamic.so /usr/lib64/libdynamic.so

4 用户登录时,系统自动执行脚本.bash_profile,这个脚本里会执行.bashrc,可以导入环境变量

为什么要有库?

1 站在使用库的角度,库的存在,可以大大减少我们开发的周期,提高软件本身质量

2 站在写库的人角度

(1) 简单

(2) 代码安全(代码不公开,源代码安全)

相关推荐
哈哈哈笑什么6 分钟前
蜜雪冰城1分钱奶茶秒杀活动下,使用分片锁替代分布式锁去做秒杀系统
redis·分布式·后端
WZTTMoon21 分钟前
Spring Boot 4.0 迁移核心注意点总结
java·spring boot·后端
寻kiki22 分钟前
scala 函数类?
后端
疯狂的程序猴32 分钟前
iOS App 混淆的真实世界指南,从构建到成品 IPA 的安全链路重塑
后端
bcbnb44 分钟前
iOS 性能测试的工程化方法,构建从底层诊断到真机监控的多工具测试体系
后端
开心就好20251 小时前
iOS 上架 TestFlight 的真实流程复盘 从构建、上传到审核的团队协作方式
后端
小周在成长1 小时前
Java 泛型支持的类型
后端
aiopencode1 小时前
Charles 抓不到包怎么办?HTTPS 抓包失败、TCP 数据流异常与底层补抓方案全解析
后端
稚辉君.MCA_P8_Java1 小时前
Gemini永久会员 C++返回最长有效子串长度
开发语言·数据结构·c++·后端·算法
Penge6661 小时前
Redis-bgsave浅析
redis·后端