🐼故事背景

假设今天你有一位舍友。你需要帮助他完成老师的作业。而他写的代码依赖两个文件(mymath.h,mystdio.h)。但是这两个文件的功能他不会写,他只会调用。他的调用代码:

#include"mystdio.h"
#include"mymath.h"
#include<string.h>
#include<unistd.h>int main()
{MYFILE* fp = myfopen("log.txt","w");if(!fp){perror("myfp");return 1;}int cnt = 20;const char* s = "hello myfile";while(cnt--){myfwrite(s,strlen(s),fp);if(cnt  ==  5){myfflush(fp);}}myfclose(fp);printf("10+20 = %d\n",Add(10,20));return 0;
}

但是你会这两个文件具体功能的实现啊。出于热心肠的你现在要帮助他。你会怎么帮助他呢?


🐼静态库制作 

1️⃣直接把源文件给他

处于热心肠的你。将你写好的代码mystd.c, mymath.c, mystdio.h, mymath.h这四个文件都给了你舍友。你的舍友通过编译链接完美应付了考试。你帮他顺利过关了。

2️⃣给他.o文件

我们知道。形成一个可执行程序最关键的步骤就是先把源文件编译成.o文件。再把这些.o文件通过链接器链接成.exe文件。如图:

你出于安全考虑,这次不给他源文件了。而是直接将链接好的.o文件交给他。并且给了他说明书(.h)文件

gcc -c *.c 

他再将他的test.c编译形成.o文件。和你给的.o大家再一链接又编译形成了可执行程序。这次又顺利过关了!

gcc -c  test.c #-rw-rw-r-- 1 lsg lsg    59 Aug  3 18:09 mymath.c
#-rw-rw-r-- 1 lsg lsg    34 Aug  3 18:09 mymath.h
#-rw-rw-r-- 1 lsg lsg  1232 Aug  3 18:17 mymath.o
#-rw-rw-r-- 1 lsg lsg  2098 Aug  3 18:09 mystdio.c
#-rw-rw-r-- 1 lsg lsg   560 Aug  3 18:09 mystdio.h
#-rw-rw-r-- 1 lsg lsg  3336 Aug  3 18:17 mystdio.o
#-rw-rw-r-- 1 lsg lsg   463 Aug  3 17:58 test.c
#-rw-rw-r-- 1 lsg lsg  2200 Aug  3 18:15 test.ogcc -o myexe *.o

3️⃣将.o文件打包形成静态库

出于安全考虑。连.o都不想给他了。于是你把你编译好.o打包形成一个静态库。交给了你的舍友并给了他说明书。

为什么能这么做呢?因为你心里清楚。静态库文件的本质就是将.obj进行打包。他的文件最后也要变成.o的。所有.o的文件链接就成了可执行程序。

你:

# 编译将所有.c形成.o 
gcc -c *.c # 将所有.o 文件打包成静态库
ar -rc libmyc.a *.o// 将形成好的libmyc.a交给你的舍友并且把说明书.h文件也给他。

你的舍友:

#直接编译链接
gcc -o myexe test.c # error

 发现报错了!为什么呢?根据报错信息。编译器不认识我给他提供的函数。于是他上网查阅。

发现需要带-l 标明要连接哪个库。因为库多了

为什么要带-l啊。为什么链接C语言不需要带-lc

因为gcc就是编译C语言的。默认就要认识。

而我们如果使用任何第三方库。至少要使用-l表明库名称,指明你要链接谁

# 表明要连接mylibc库
gcc -o myexe test.c -lmyc
# 注意 lib 和.a不需要带

但是发现还是不行根据报错原因。原来是库路径找不到(编译器不认识)。

通过-L指定你要链接库的位置(搜索目录)

gcc -o myexe test.c -L. -lmyc 

链接成功!

但是你的舍友想把#include"mystdio.h"   #include"mymath.h"换成#include <mystdio.h>
#include <mymath.h> 可以吗?

通过-I指定一个搜索路径。表明头文件搜索路径。这样编译器默认从指定的路径下查找依赖头文件

gcc -o myexe test.c -L. -lmyc -I.

通过上述做法。你的舍友就成功的使用了你给他提供的静态库! 


✅但是当你舍友查看库所依赖的文件时。发现并没有查到libmyc.a,这是为什么??

ldd myexelinux-vdso.so.1 (0x00007ffc62cb8000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0a80d2d000)/lib64/ld-linux-x86-64.so.2 (0x00007f0a80f64000)

因为链接的是静态库。静态库本质是.o文件的集合。一旦链接,形成.exe,就不再依赖静态库了。因为静态库早已合并自已的代码到可执行程序中了

✅现在还有一个问题。就是为什么我们链接其他库时(比如pthread库)。并不需要带-L -I 这样的选项。

其实当库没有在系统默认的路径下时。gcc/g++编译器找库。默认会在系统默认路径下查找,而所谓库的安装。就是把库文件拷贝到系统默认路径下。

这里以ubuntu为例。我的库文件系统默认路径是/lib/x86_64-linux-gnu/ (怎么找的,ldd 查看/usr/bin/ls依赖的系统库目录即可)

这是不是意味着。只要我们把库文件拷贝到/lib/x86_64-linux-gnu/。就不用带-L选项。编译器能根据系统指定路径来找到我们的库目录。

并且只要我们把头文件拷贝到/usr/include/ 。就不用带-I选项。编译器能根据系统指定路径来找到我们的源文件依赖的头文件目录。

# 拷贝库文件到系统指定目录下 --->省去了 -L
sudo cp *.a /lib/x86_64-linux-gnu/# 拷贝头文件到系统执行目录下  ---> 省去了 -I
sudo cp *.h /usr/include/# 直接连接我们的库即可 -l必须带!!!(因为是第三方库)
gcc -o myexe test.c -lmyc

所以库安装的本质就是将头文件和库文件根据特定目录结构组织好拷贝到系统指定目录下,编译器默认能够找到的目录下!

☑️最佳实践

如果我们想批量化的向别人提供我们写好的库,并以库文件,头文件目录形式打包给给人使用。可以借助Makefile:

开发者:

# 将所有.o打包形成 .a
libmyc.a: mystdio.o mymath.oar -rc $@ $^# 编译并将.c->.o
%.o:%.cgcc -c $<.PHONY:clean
clean: rm -rf *.a *.o output *.tgz# 发布
.PHONY:output
output:mkdir -p outputmkdir -p output/lib/mkdir -p output/include/cp *.h output/includecp *.a output/lib/tar -czf mylib.tgz output

使用者: 

tar -xzf mylib.tgz 
# 最终将目录树长这样
#tree output
#output
#├── include
#│   ├── mymath.h
#│   └── mystdio.h
#└── lib
#    └── libmyc.agcc -o myexe test.c -I./output/include/ -L./output/lib -lmyc

如果嫌麻烦。开发者也可以在安装时。自带一个脚本帮使用者把库文件和头文件。拷贝到系统指定目录下。这样就不需要使用者指定头文件位置和库文件位置了


🐼动态库制作

跟形成静态库原理类似。

第一步。将源文件.c编译形成.o文件。注意。在编译形成.o文件时。要带上-fPIC(与位置无关码)

# .c -> .o
gcc -fPIC -c *.c

将.o打包形成动态库

gcc -o libmyc.so *.o -shared

编译并链接动态库

gcc -o myexe test.c -lmyc -L. -I.

运行程序。./myexe

结果报错了!why???

#./myexe
#./myexe: error while loading shared libraries: libmyc.so: cannot open shared object file: #No such file or directory#lsg@hcss-ecs-0228:~/code/code/25_8_3/person$ ldd myexe
#	linux-vdso.so.1 (0x00007ffd9d53f000)
#	libmyc.so => not found
#	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbb1946d000)
#	/lib64/ld-linux-x86-64.so.2 (0x00007fbb196a4000)

我们不是已经告诉了系统。库在哪个路径下吗。为什么还是会报错呢? 并且在链接这个库时。系统找不到。这是为什么?

因为我们只告诉了编译器。我们的动态库在哪。而动态库是运行时才会加载到内存中。而此时已经和编译器无关了。所以结论就是在加载可执行程序的时候,也要找到所依赖的库。换句话说。为了运行时,系统(加载器)也能找到动态库,我们需要将库显示拷贝到系统指定目录下。当然,这只是方法之一。只要保证系统(加载器)在加载动态库时也能找到动态库即可。

sudo cp libmyc.so /lib/x86_64-linux-gnu/ #ldd myexe
#	linux-vdso.so.1 (0x00007ffc7834c000)
#	libmyc.so => /lib/x86_64-linux-gnu/libmyc.so (0x00007f2c3c987000)
#	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2c3c75e000)
#	/lib64/ld-linux-x86-64.so.2 (0x00007f2c3c99a000)

我们也可以通过软链接的方式关联将库文件的安装目录进行关联 

我们将动态库也以目录形式打包发布出去:

如果我们自已使用(软连接可以根据你的绝对路径修改,这里小编就不改了)

libmyc.so:mystdio.o mymath.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf  *.o *.so sudo unlink /lib/x86_64-linux-gnu/libmyc.so sudo unlink /usr/include/mymath.h  sudo unlink /usr/include/mystdio.h.PHONY:self
self:sudo ln -s /home/lsg/code/code/25_8_3/mylib/libmyc.so /lib/x86_64-linux-gnu/libmyc.sosudo ln -s /home/lsg/code/code/25_8_3/mylib/mymath.h /usr/include/mymath.hsudo ln -s /home/lsg/code/code/25_8_3/mylib/mystdio.h /usr/include/mystdio.h// 自已写的库完全可以拷贝到系统指定目录下。就不用软连接了(软连接只能在你指定的路径下使用你的库)

☑️最佳实践

如果我们自已想用自已写好的库,直接拷贝到系统指定目录下!

libmyc.so:mystdio.o mymath.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf  *.o *.so sudo rm /lib/x86_64-linux-gnu/libmyc.so sudo rm /usr/include/mymath.h mystdio.h .PHONY:copy
copy:sudo cp mymath.h mystdio.h /usr/include/sudo cp libmyc.so /lib/x86_64-linux-gnu/

发布给别人使用

libmyc.so:mystdio.o mymath.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf output *.o *.so *.tgz.PHONY:output
output:mkdir -p output mkdir -p output/lib/mkdir -p output/include/cp *.h output/include/cp *.so output/lib/tar -czf mylib.tgz output

当然。运行时找到动态库的原理还有几种。比如配置 LD_LIBRARY_PATH环境变量。

更改系统配置文件。将动态库,查找路径,使其全局有效。

还需要注意的是:

✅动态库和静态库同时存在的时候,gcc/g++优先使用动态库。默认进行动态链接!

✅一个可执行程序。可能依赖多个库,但是如果我们只提供静态库,即使动态链接。gcc也没办法,只能对只提供的静态的库,进行静态链接!

✅如果我们显示带上-static选项。那么我们就一定要提供静态库了,否则,会报错! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917825.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917825.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917825.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Database Navigator插件进行连接sqlite报错invalid or incomplete database

解决方案 &#xff0c;将这个db.sqlite3文件拷贝到盘的文件中 &#xff0c;修改文件夹名字&#xff0c;重新使用绝对路径访问 db.sqlite3&#xff0c;将路径名字的中文去掉 &#xff0c;不能有中文

【Linux】重生之从零开始学习运维之主从MGR高可用

MGR集群部署12、15、18主机环境准备ssh免密码登录\rm -rf .ssh/* ssh-keygen ssh-copy-id 127.1 scp -r .ssh 10.0.0.12:/root/ ssh root10.0.0.12还原基础环境systemctl stop mysqld \rm -rf /var/lib/mysql/* id mysqlvim /etc/my.cnf.d/mysql-server.cnf [mysqld] datadir/v…

如何在虚拟机(Linux)安装Qt5.15.2

1.进入到阿里的网站下载在线安装包 qt-official_releases-online_installers安装包下载_开源镜像站-阿里云 https://mirrors.aliyun.com/qt/official_releases/online_installers/?spma2c6h.13651104.d-5201.2.60ad4773ZZNPNm 2.下载完毕后&#xff0c;进入到下载地址&…

【运维进阶】DHCP服务配置和DNS域名解析

DHCP服务配置和DNS域名解析 DHCP 服务介绍 在大型网络中&#xff0c;系统静态分配IP地址面临问题&#xff1a; 确保不要同时在多个系统上使用同一个地址。部署新系统通常需要手动分配其IP地址。在云环境中&#xff0c;实例的网络是自动化配置的。 动态主机配置协议&#xff08;…

VisionPro MR环境下虚拟物体与现实的透明度混合

display.rgb (virtualcontent.rgb*1)(passthrough.rgb*(1 - vistualcontent.a) viirtualcontent预乘过a值了&#xff0c;跟透明度混合公式一致 人头检测挖孔不清晰问题&#xff0c;这个a值变成设备层动态检测人头的a值&#xff0c;当面前的渲染压力过大时&#xff0c;会导致…

css怪异模式(Quirks Mode)和标准模式(Standards Mode)最明显的区别

文章目录css怪异模式&#xff08;Quirks Mode&#xff09;和标准模式&#xff08;Standards Mode&#xff09;最明显的区别详细对比示例对比&#xff08;盒模型&#xff09;标准模式&#xff08;Standards Mode&#xff09;怪异模式&#xff08;Quirks Mode&#xff09;如何触发…

一种简单的3dnr去噪算法介绍

一段未经过插补的视频图像可以分解为若干帧&#xff0c;为了能正确地找到并去除图像帧中的噪声污染&#xff0c;由于视频图像各帧的连续性&#xff0c;在去噪的过程中就必须考虑帧图像的空间性和时间性&#xff0c;一个简单的例子&#xff0c;在去噪算法中就必须考虑&#xff0…

【数据结构初阶】--排序(四):归并排序

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言&#xff1a;生活是默默的坚持&#xff0c;毅力是永久的…

GaussDB 并行创建索引

1 背景当业务数据在单表存储达到一定的数量级时&#xff0c;此时对表创建索引是要花费时间的。GaussDB为了解决这个问题采用并行创建索引技术&#xff0c;以提高创建索引的效率。2 示例步骤1&#xff1a;根据实际情况调整maintenance_work_mem参数该大小。[Rubydtest1 ~]$ gsq…

LOOP Finance:一场 Web3 共和国中的金融制度实验

LOOP Finance 是建构于币安智能链&#xff08;BNB Chain&#xff09;上的定投型DEFI理财协议。 它以凯因斯经济学为启发&#xff0c;设计出一套长期、安全、稳定收益的全新DEFI玩法&#xff0c;兼顾稳健利息回报与DEFI高速成长的潜力。 通过生态机制&#xff0c;LOOP要求每位参…

【golang面试题】Golang递归函数完全指南:从入门到性能优化

引言&#xff1a;递归的本质与挑战 在Golang中&#xff0c;递归函数是一把锋利的双刃剑。它通过函数自身调用实现问题分解&#xff0c;让代码变得简洁优雅&#xff0c;但也容易因无限递归、栈溢出或性能问题让开发者陷入困境。本文将从基础到高级&#xff0c;全面解析Golang递归…

功能安全和网络安全的综合保障流程

摘要网络物理系统是控制机械部件的计算机化系统。这些系统必须既功能安全又网络安全。因此&#xff0c;已建立的功能安全与网络安全标准需求创建网络安全档案&#xff08;ACs&#xff09;&#xff0c;以论证系统是功能安全与网络安全的&#xff0c;即所有功能安全与网络安全目标…

数据科学首战:用机器学习预测世界杯冠军

数据科学首战&#xff1a;用机器学习预测世界杯冠军Scikit-learn实战&#xff1a;从数据清洗到冠军预测的完整指南一、足球预测&#xff1a;数据科学的终极挑战​​世界杯数据价值​​&#xff1a;历史比赛数据&#xff1a;44,000场球队特征指标&#xff1a;200球员数据点&…

一个php 连sqlserver 目标计算机积极拒绝,无法连接问题的解决

一个接口查询数据耗时15秒&#xff0c;还没数据&#xff0c;经查报错日志&#xff1a;SQLSTATE[08001]: [Microsoft][ODBC Driver 17 for SQL Server]TCP 提供程序: 由于目标计算机积极拒绝&#xff0c;无法连接。 命令行执行&#xff1a;netstat -ano | findstr :1433发现结…

生成网站sitemap.xml地图教程

要生成 sitemap.xml 文件&#xff0c;需要通过爬虫程序抓取网站的所有有效链接。以下是完整的解决方案&#xff1a; 步骤 1&#xff1a;安装必要的 Python 库 ounter(line pip install requests beautifulsoup4 lxml 步骤 2&#xff1a;创建 Python 爬虫脚本 (sitemap_genera…

idea拉取新项目第一次启动报内存溢出(java.lang.OutOfMemoryError: Java heap space)

背景&#xff1a; 新拉取一个项目后&#xff0c;第一次启动的时候报错内存溢出&#xff1a; Java 堆内存溢出 (java.lang.OutOfMemoryError: Java heap space) 这个错误表示你的 Java 应用程序需要的内存超过了 JVM 堆内存的分配上限。 解决方案 1.增加堆内存大小 启动应用时添…

安卓雷电模拟器安装frida调试

1.在模拟器中设置调试root和adb 2.在vscode中安装autox.js 3.在github上下载auto.js组件 新地址链接看来大佬的项目也经历了波折https://blog.csdn.net/weixin_41961749/article/details/145669531 github地址https://github.com/aiselp/AutoX/releases 将下载的apk放入雷电…

Godot ------ 初级人物血条制作02

Godot ------ 初级人物血条制作02引言正文血条动态显示引言 在 Godot ------ 初级人物血条制作01 一文中我们介绍了如何构建一个初级血条&#xff0c;但是我们并没有涉及如何动态显示血条。本文我们将介绍如何动态显示血条。 正文 血条动态显示 首先&#xff0c;我们为当前…

(Python)待办事项升级网页版(html)(Python项目)

源代码&#xff1a; app.py from flask import Flask, render_template, request, redirect, url_for, jsonify import json import osapp Flask(__name__)# 数据存储文件 DATA_FILE "todos.json"def load_todos():"""从文件加载待办事项"&q…

智慧养老破局:科技如何让“老有所养”变成“老有优养”?

随着人口老龄化加剧&#xff0c;“养老”成了社会关注的焦点。传统养老往往停留在“有地方住、有人照顾”的基础需求&#xff0c;而智慧养老则通过科技与人文的结合&#xff0c;让老年人的生活从“老有所养”升级到“老有优养”。不仅活得安心&#xff0c;更能活得有尊严、有质…