当前位置: 首页 > news >正文

完整教程:OS39.【Linux】动态库和静态库 自制静态库

目录

1.知识回顾

提供方法的两种形式

2.自制静态库并使用

新建两个文件

生成静态库文件的方法

编写Makefile,生成静态库文件

解释ar -rc命令的作用

发布静态库

使用静态库

第一版代码

第二版代码

第三版代码

3.总结

4.补: gcc的搜索路径


1.知识回顾

之前在OS12.【Linux】gcc和g++以及动静态链接文章感性认识过动态链接和静态链接,这里贴上部分内容:

动态链接: 程序运行时加载和链接库文件,换而言之,动态库是依附于可执行文件创建的进程来执行的,可执行文件自己不带动态链接库,需要到系统中调用动态链接库,完成后返回代码的调用处

静态链接: 和动态链接不同,编译器使用静态库进行静态链接时,会将自己方法拷贝到目标程序中,程序在调用静态链接库的方法时不会转到系统中的动态链接库中执行

其次,动态链接: 链接的是lib*.so文件 静态链接: 链接的是lib*.a文件

提供方法的两种形式

1.直接提供方法的源代码,开发者需要自行编译

2.把方法的源代码想办法打包成库,向开发者提供库文件(实现) + 头文件(声明)

注意: 不可以只给库文件! 因为需要头文件来作库文件的说明书

2.自制静态库并使用

新建两个文件

新建static_lib.c和static_lib.h,其中方法声明在h文件,方法实现在c文件

static_lib.c:

写一个简单的函数,方便演示

double mydiv(double x,double y)
{return x/y*1.0;
}

static_lib.h:

#pragma once
double mydiv(double x,double y);

static_lib.h提供了mydiv方法的声明,static_lib.c提供了mydiv方法的实现

生成静态库文件的方法

回顾生成可执行文件的的过程:90.【C语言】编译和链接

预处理(预编译)→编译→汇编→链接

多个源文件生成多个目标文件,之后将多个目标文件链接起来,

生成静态库文件这样做的:将所有o文件的集合(不含main函数的源文件生成的o文件)打包(ar命令)为静态库,然后让main.c使用,生成最后的可执行文件

编写Makefile,生成静态库文件

lib=libdiv.a
$(lib):static_lib.oar -rc $@ $^
static_lib.o:static_lib.cgcc -c $^
.PHONY:clean
clean:rm -f :static_lib.o libdiv.a

看看依赖关系: static_lib.c→static_lib.o→libdiv.a,而libdiv.a就是静态库文件

注意: 静态库的名称必须按照lib*.a格式来,否则gcc报错

解释ar -rc命令的作用

ar是gnu归档(archives)工具,rc表示(replace and create)

r选项: 在归档文件中替换已存在的成员

        如果指定的文件在归档中不存在,其会被添加到归档的末尾

c选项: 如果归档文件不存在,则创建归档文件,否则ar命令会报警告

发布静态库

将库文件放到一个目录中,头文件放到另外一个目录中,为Makefile添加以下内容:

.PHONY:release
release:mkdir -p lib/includemkdir -p lib/libdivmv libdiv.a lib/libdiv/libdiv.amv static_lib.h lib/include/static_lib.h

使用静态库

编写main.c

第一版代码

#include 
#include "static_lib.h"
int main()
{printf("1 / 2 =  %lf\n",mydiv(1,2));
}

报错是因为找不到头文件

gcc是这样寻找头文件的:

对于像#include " "这样包含的头文件,如果不带路径,只有头文件的名称,那么gcc首先在自己当前所处的目录中找 2.如果第第一步找不到,那么就在系统的头文件的存储目录中找

头文件的存储目录存放在环境变量中,一般是/usr/include

第二版代码

为了方便起见,不将static_lib.h所处的理解添加到gcc搜索头文件的路径上,直接在源文件中指定

可以使用绝对路径:

#include 
#include "/home/guest/lib/include/static_lib.h"
int main()
{printf("1 / 2 =  %lf\n",mydiv(1,2));
}

也可以使用相对路径:

#include 
#include "lib/include/static_lib.h"
int main()
{printf("1 / 2 =  %lf\n",mydiv(1,2));
}

但无论哪种写法都会报链接错误:

虽然能找到头文件,头文件承诺有mydiv函数,但是gcc找不到mydiv方法实现(即libdiv.a静态库文件),一般gcc默认在/lib64中找库文件,那么应该为gcc指定库的路径

查阅gcc官方手册Using the GNU Compiler Collection For gcc version 15.2.0知道:

摘录部分内容

3.16 Options for Linking

-llibrary
-l library
Search the library named library when linking. (The second alternative with
the library as a separate argument is only for POSIX compliance and is not
recommended.)
The -l option is passed directly to the linker by GCC. Refer to your linker
documentation for exact details. The general description below applies to the
GNU linker.
The linker searches a standard list of directories for the library. The directories
searched include several standard system directories plus any that you specify
with -L.
Static libraries are archives of object files, and have file names like
liblibrary.a. Some targets also support shared libraries, which typically
have names like liblibrary.so. If both static and shared libraries are
found, the linker gives preference to linking with the shared library unless the
-static option is used.
It makes a difference where in the command you write this option; the linker
searches and processes libraries and object files in the order they are specified.
Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o.
If bar.o refers to functions in ‘z’, those functions may not be loaded.

这里使用-L选项:

gcc main.c -L ./lib/libdiv/

但仍然报链接错误:

原因:-L只是告诉了库文件的路径,一个目录里面可能有很多库文件,但gcc不知道链接哪个库文件,因为上方的命令中没有指定库名

可以使用-l来指定库:

#源文件已经指定头文件的路径
gcc main.c -L ./lib/libdiv/ -ldiv

注:库的完整名称是libdiv.a,只需要-ldiv(-l(小写的l)后紧跟着库名,库名是去掉前缀和后缀剩下的部分,不需要写前面的lib和后面的.a)

运行结果:

第三版代码

如果这样写:

#include 
#include "static_lib.h"
int main()
{printf("1 / 2 =  %lf\n",mydiv(1,2));
}

那么gcc需要知道static_lib.h的路径,可以使用-I(大写的i)来指定头文件的搜索路径:

gcc main.c -L ./lib/libdiv/ -ldiv -I ./lib/include

3.总结

用ldd查看a.out的动态库:

ldd的作用是显示可执行文件的动态库,自制的是静态库,因此ldd是不会显示的,上图从侧面来看: 一个可执行程序的动态库和静态库是可以共存的

注意gcc使用静态库编译的细节:

由于gcc默认采用动态链接的方式(言外之意: 如果系统中只提供静态链接库而且用户也没有提供动态链接库,那么gcc 则只能对该库进行静态链接),那么想让gcc编译自制的静态库是需要添加一些选项的

细节一: 给头文件路径: gcc的-I(大写的i)选项或者直接在源代码里面指定相对路径或决定路径)

细节二: 给库文件路径: gcc的-L

细节三: 给库文件名: gcc的-l (小写的l,即link)

如果系统中需要链接多个库,则gcc可以链接多个库

结论: 链接第3方库必须告诉gcc的头文件路径和库文件路径和库文件名称

如果不想写那么多选项,可以这样做:

头文件拷贝到系统的include目录,库文件拷贝到系统的lib目录

或者:

将软链接放到gcc的搜索路径下

★其实不建议将自制的库文件放到系统的默认搜索路径下,容易和系统的库文件冲突

4.补: gcc的搜索路径

gnu gcc官网给出了搜索路径: https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html

其指出: 默认的搜索路径和特定的系统、gcc的配置和安装路径有关,可以通过-v选项来查看搜索路径,例如:

gcc -v /dev/null -o /dev/null
http://www.jsqmd.com/news/337617/

相关文章:

  • 基于STM32的麦克风阵列近场声源定位系统
  • 高压尼龙颗粒哪家好?通腾塑业带来的生产经验分享与对比观察 - 企师傅推荐官
  • SVN版本控制工具
  • 2026年广州水晶滴胶厂家最新推荐榜:亚克力水晶滴胶、冰箱贴水晶滴胶、透明水晶滴胶、反光膜水晶滴胶、果冻水晶滴胶、聚焦产品品质与品类竞争力深度剖析 - 海棠依旧大
  • 2026年不干胶标签厂家推荐排行榜:电池贴标/卷筒标签/双面胶贴/易碎标签/条码标签/透明标贴/烫金标/热敏打印标签/条形码流水号,专业定制与高粘品质之选 - 品牌企业推荐师(官方)
  • 中学生护眼台灯怎么选?权威测评-学生读写首选专业读写护眼台灯 - 资讯焦点
  • 给孩子补钙可以喝什么品牌的牛奶?2026年值得关注的三种补钙牛奶及选购要点 - Top品牌推荐
  • 美国财务分析求职辅导哪家强:权威辅导深度报告 - 技研备忘录
  • 美国SDE求职机构哪家强:SDE机构TOP10 - 技研备忘录
  • 项目经理与甲方沟通的十大禁忌,你踩过几个?
  • 水晶滴塑、水晶滴胶厂家哪家实用性强?2026年榜单这几家靠谱企业值得关注! - 海棠依旧大
  • 2026年 包装盒厂家推荐排行榜:白盒/白卡盒/双插盒/扣底盒/彩盒印刷/天地盖/飞机盒/纸套/封套/盒套/抽屉盒/瓦楞盒,匠心定制与创新设计之选 - 品牌企业推荐师(官方)
  • 2026年 浮筒厂家推荐排行榜:浮桶/浮箱/组合式浮筒/模块/游艇码头/水上平台/景观浮桥/养殖网箱/河道拦污浮筒,精选耐用抗腐蚀水上解决方案! - 品牌企业推荐师(官方)
  • 【Linux命令大全】009.备份压缩之compress命令(实操篇)
  • Unity3D 八大菜系连连看
  • 2026 AI玩具价值榜:谁把“教育+安全+陪伴”一次做对了? - 品牌策略主理人
  • 连云港本地生活代运营谁更强?这份实力榜单给出答案 - 野榜数据排行
  • 采购机床找平台哪个好?5大主流平台深度对比,帮你避坑选对 - 品牌推荐大师1
  • 自动化测试用例编写详解
  • 分析2026年适合大面积铺贴的知名木纹砖品牌怎么收费 - 工业设备
  • Linux驱动开发:从一个最简单的模块开始
  • 聊聊北大青鸟岳麓校区,长沙株洲湘潭地区性价比如何 - 工业推荐榜
  • 【Linux命令大全】009.备份压缩之cpio命令(实操篇)
  • 【行业盘点】凯氏定氮仪十大品牌厂家排行榜,实力与口碑兼具 - 品牌推荐大师1
  • 2026年聊聊山西仓储货架,正规厂家怎么选择? - 工业品网
  • 大叔学springboot ,且学且记
  • 盘点河北螺母供应商直销公司Top10,企业实力大揭秘 - 工业推荐榜
  • 2026年讲讲木制包装箱定制厂哪个值得选,哈尔滨靠谱厂家推荐 - 工业品牌热点
  • 优秀的项目经理需要具备哪些品质?
  • leetcode 893. Groups of Special-Equivalent Strings 特殊等价字符串组-耗时100