初识linux(16) 动静态库(手搓动静态库!)

news/2025/3/18 23:46:41/

目录

前导回顾

1. 手搓静态库

step1  编译获得同名.o文件

step2 ar -rc指令建立库

step3 将库安装到对应的路径下去

安装方法1:先将头文件都装到 /usr/include 路径下,再将库文件装到/lib64/ 路径下。

安装方法2:不安装到系统,在一个文件夹中使用

插曲:在makefile中完成编译与打包(便于讲解安装方法3) 

安装方法3:打包到其他文件夹使用

2. 手搓动态库

两种方法解决库运⾏搜索路径

1.在lib64中添加对应的.so库

2. 直接添加环境变量


前导回顾

什么是库
库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个⼈的代码都从零开始,因此库的存在意义⾮同寻常。
比如我们的<iostream>,<cstdlib>等等都是我们对库复用的体现。
静态库与动态库
举个例子,在写论文的时候,引用一句话,但是不将整篇文章都抄进去,而是将出处写在末尾,这就是动态库;但是如果将整篇文章都直接复制进去了,就是静态库
由此可见,静态库空间更大更笨,但是是在编译时直接编译好的,形成一个可执行程序,编译好之后就不依赖外部实现;动态库更省空间,但是是在程序运行时需要使用这个库的时候再去链接,依赖外部实现。

库文件的格式

静态库 .a[Linux] .lib[windows]
动态库 .so[Linux] .dll[windows]
注意, 本质上来说库是⼀种可执⾏代码的⼆进制形式,可以被操作系统载⼊内存执⾏。
因此库一定不是.c文件,而是.o文件的一个“集合”。

1. 手搓静态库

初识Linux(13) 由基础IO知识简易封装stdio.h中的FILE-CSDN博客

(FILE就是C语言中描述文件的结构体,常用于:FILE* fp = fopen("log.txt","w" )等等,借助我们之前实现的库来完成以下操作) 

学习指令: 

$ ar   -rc   libmystdio.a   my_stdio.o my_string.o

ar是gnu下的归类工具,专门用于创建、修改和管理静态库(archive)的工具

r和c表示replace和create,也可以使用t指令来查看库的情况。

总的来说,库必须使用.o文件作为成员文件,避免了暴露源代码。

step1  编译获得同名.o文件

step2 ar -rc指令建立库

库的名字必须是lib开头,.a结束,.a结束后面可以跟版本等信息

如果多个文件:

如果一个文件:

step3 将库安装到对应的路径下去

安装方法1:先将头文件都装到 /usr/include 路径下,再将库文件装到/lib64/ 路径下。

                 

此时vim 一个main.c,已经能查看到我们自己的头文件可以使用了

             

假设此函数中国,我们只使用mfopen,退出vim后开始编译

出现一个链接式报错!

此时应该在gcc时加上-l指令

这是常见错误。

库的名字要去掉前缀和后缀,就能正常编译了。

也可以继续沿用刚刚的指令。

gcc -l

引入指定名字的第三方库。

-l后面直接接库名字,l表示link


安装方法2:不安装到系统,在一个文件夹中使用

如果不安装到系统中,只是 在一个文件夹中想使用:

首先是认不到头文件(因为没有放到/usr/include里!),

<>改" ",表示去包含当前路径下的自己实现的头文件。

                           

依然找不到,因为:gcc -l在查的时候默认在系统路径下找。

引入: gcc -L,告诉gcc查找库的时候也在-L后面的路径中找。


插曲:在makefile中完成编译与打包(便于讲解安装方法3) 

形成库与清理:

                                         

发布:

将写好的库和头文件打包到一个文件夹中去。

还可以再压缩一下:

  1 ibmstdio.a:mstdio.o2   @ar -rc $@ $^3 %.o:%.c4   @gcc -c $<5 6 .PHONY:7 clean:8   @rm -rf *.a *.o stdc9   @echo "clean done"10 11 .PHONY:12 output:13   @mkdir -p stdc/include14   @mkdir -p stdc/lib 15   @cp -f *.h stdc/include16   @cp -f *.a stdc/lib 17   @tar -czf stdc.tgz stdc   

模拟真实使用情景。

安装方法3:打包到其他文件夹使用

这样,在其他文件夹中,可以通过拷贝直接使用了:

将stdc.tar拷贝到一个新文件夹other中,先解压,不过当前的main函数和stdc中的内容还不在一个目录下。

             

因此,在main中想通过"mstdio"去找头文件也不现实。

引入gcc -I(大写i),在指定路径下去找头文件;-L只能告诉要在哪个文件夹里面链接,-l说明具体链哪个库。一个-I(大i)就能直接让gcc去里面找头文件

[lsnm]$ gcc main.c -Istdc/include -Lstdc/lib -lmstdio -o myexe

小结gcc在编译库三个问题:

头文件路径找不到(-I),库路径找不到(-L),库名称找不到(-l)


2. 手搓动态库

动态库(.so):程序在运⾏的时候才去链接动态库的代码,多个程序共享使⽤库的代码。
⼀个与动态库链接的可执⾏⽂件仅仅包含它⽤到的函数⼊⼝地址的⼀个表,⽽不是外部函数所在⽬标⽂件的整个机器码
在可执⾏⽂件开始运⾏以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中, 这个过程称为动态链接(dynamic linking)
        动态库可以在多个程序间共享,所以动态链接使得可执⾏⽂件更⼩,节省了磁盘空间。操作系统采⽤虚拟内存机制允许物理内存中的⼀份动态库被要⽤到该库的所有进程共⽤,节省了内存和磁盘空间。

动态库的命名一样,必须前缀lib开头,后缀是.so

形成库文件的时候直接用gcc,我们在之前静态库的makefile的基础上直接改写:

gcc -shared

gcc -fPIC

                     

-shared告诉gcc,生成的是一个.so动态库。而不是一个可执行程序

-fPIC让.o的链接信息里包含“位置无关码”(知道即可)

同样的三种方法:

直接拷进系统:

 就在本地使用:

顺便可以使用ldd查依赖的库,或测试一下动态库的特点:生成可执行程序之后删库,看一下是否还能运行。

不如果是静态库的话,只要实现了可执行程序,删库也一样能跑

动态库的编译和静态库一致,就算在同一文件下, 也要先说明-L.(在当前路径下找库),-l mystdio(在路径中找哪个库)

拷贝解压之后其他目录下使用:

gcc main.c -o myexe -Istdc/include -Lstdc/lib -lmstdio

编译成功,但却跑不起来。

因为系统找不到.so库!刚刚的操作是让编译器找到了.so库,执行程序时,操作系统将程序加载到内存,此时找不到了。

两种方法解决库运⾏搜索路径

如何告诉系统查找自己动态库的路径呢?系统通过查以下环境变量来确定找库的路径

环境变量:LOAD_LIBARY_PATH(整个环境变量中最长最大的那一个!)

使用env指令查看:

LOAD_LIBARY_PATH中包含了/lib64以及当前路径 

也就是对应的第一种和第二种安装方法都是可行的

1.在lib64中添加对应的.so库

除了可以直接拷贝,也可以使用一个软链接的方式将当前的libmstdio.so给ln到/lib64中

这个时候ldd就能查到库对应的信息了。

采用unlink再回到刚刚的状态,便于后续实验。

2. 直接添加环境变量

直接export,将希望的路径给加进去

偏底层的路径,建议都使用绝对路径!!


在以前提到过,如果动静态库同时存在,系统会使用动态库。

强制静态库:在编译的时候加一个-static



http://www.ppmy.cn/news/1580185.html

相关文章

Anaconda 入门指南

Anaconda 入门指南 一、下载安装 Anaconda 1、下载地址&#xff1a;Anaconda 推荐下载 python3 版本, 毕竟未来 python2 是要停止维护的。 2、安装 Anaconda 按照安装程序提示一步步安装就好了, 安装完成之后会多几个应用&#xff1a; Anaconda Navigtor &#xff1a;用于管…

《解锁C语言逻辑操作符的“魔法力量”》

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 一、初识逻辑操作符&#xff08;一&#xff09;逻辑与&#xff08;&&&#xff09;&#xff08;二&#xff09;逻辑或&#xff08;||&#xff09;&am…

Blender-MCP服务源码3-插件开发

Blender-MCP服务源码3-插件开发 Blender-MCP服务源码解读-如何进行Blender插件开发 1-核心知识点 1&#xff09;使用Blender开发框架学习如何进行Blender调试2&#xff09;学习目标1-移除所有的Blender业务-了解如何MCP到底做了什么&#xff1f;3&#xff09;学习目标2-模拟MC…

Webpack 和 Vite 的主要区别

Webpack 和 Vite 的主要区别&#xff0c;从构建机制、开发体验、生产优化等多个维度进行对比&#xff1a; 1. 构建机制与速度 Webpack 全量打包&#xff1a;启动时必须分析所有模块依赖关系&#xff0c;进行全量打包&#xff0c;生成 Bundle 文件。项目越大&#xff0c;冷启动时…

Blender选择循环边/循环面技巧

循环边和循环面都是有方向的 可以按方向选取相对应的循环边/循环面 按住ShiftAlt左键单击 竖着的边就会选择竖着的循环面 按住ShiftAlt左键单击 横着的边就会选择横着的循环面 也没人讲过这个 自己摸索出来的 , 真是踩坑无数 , 今天终于知道了...

odbus TCP转Modbus RTU网关快速配置案例

Modbus TCP 转Modbus RTU网关快速配置案例 在工业自动化领域&#xff0c;Modbus 协议以其简洁和高效而著称&#xff0c;成为众多设备通信的首选。 随着技术的发展和应用场景的变化&#xff0c;Modbus 协议也发展出了不同的版本&#xff0c;其中 Modbus TCP 和 Modbus RTU 是两种…

算是解决可以访问github但无法clone的问题

本文的前提是使用了**且可以正常访问github 查看代理的端口 将其配置到git 首先查看git配置 git config --list然后添加配置&#xff0c;我这边使用的是Hiddfy默认的端口是12334&#xff0c;如果是clash应该是7890 git config --global http.proxy 127.0.0.1:12334其他 删除…

C语言的软件工程

C语言的软件工程 引言 C语言作为一种历史悠久、功能强大的编程语言&#xff0c;在软件工程领域有着广泛的应用。自1972年由Dennis Ritchie开发以来&#xff0c;C语言凭借其高效性能、灵活性以及可移植性&#xff0c;成为了操作系统、嵌入式系统及高性能应用程序开发的首选语言…