动态库和静态库

动态链接和静态链接

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) 代码安全(代码不公开,源代码安全)

相关推荐
Q_19284999067 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
ZSYP-S35 分钟前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
Yuan_o_1 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
程序员一诺2 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
DT辰白2 小时前
如何解决基于 Redis 的网关鉴权导致的 RESTful API 拦截问题?
后端·微服务·架构
thatway19893 小时前
AI-SoC入门:15NPU介绍
后端
陶庵看雪3 小时前
Spring Boot注解总结大全【案例详解,一眼秒懂】
java·spring boot·后端
Q_19284999063 小时前
基于Spring Boot的图书管理系统
java·spring boot·后端
ss2733 小时前
基于Springboot + vue实现的汽车资讯网站
vue.js·spring boot·后端
一只IT攻城狮4 小时前
华为云语音交互SIS的使用案例(文字转语音-详细教程)
java·后端·华为云·音频·语音识别