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

Linux的动态库和静态库

文章目录

    • 前言
    • 动静态库概念补充
    • 制作静态库
      • 静态库的打包
      • 链接静态库
    • 制作动态库
      • 动态库的打包
      • 链接动态库
      • 加载动态库


前言

如果我们想把我们的方法给别人用,有什么办法呢?

  1. 把源文件直接给他
  2. 把我们的源代码打包成库(头文件+库)。

在过去学习gcc/g++工具的时候简单初步介绍了一下它们的概念:Linux开发工具的使用(二):gcc/g++与make/makefile,相似内容不再过多赘述,本文重心将放在库的制作与使用上。

动静态库概念补充

我们知道,库是由一个或多个被编译好的.o文件打包而成的,也就是说库与我们写好的.o文件一同链接为可执行程序的话,库的源代码就也是我们程序的一部分了。

库的命名规则

库分为静态库和动态库,它们的命名有所区别:

  • 动态库:libXXX.solib为前缀,.so为后缀
  • 静态库:libXXX.alib为前缀,.a为后缀

例如libstdc++.so.6,去掉前缀跟后缀,最终库名为 stdc++。

库的搜索路径:

  1. 由系统指定的目录
    Linux系统中,库文件和头文件分布在多个标准目录中。
    库文件:
  • /usr/lib/ - 32位系统的主要库文件路径
  • /usr/lib64/ - 64位系统的主要库文件路径
  • /lib/ - 系统核心库
  • /lib64/ - 64位系统核心库
  • /usr/local/lib/ - 本地安装软件的库文件
  • /opt/ 下某些软件的库文件
    在这里插入图片描述

头文件:

  • /usr/include/ - 系统主要头文件
  • /usr/local/include/ - 本地安装软件的头文件
  • 各个软件包特定的include目录
    在这里插入图片描述
  1. 由环境变量指定的目录 (LIBRARY_PATH
    后文会讲
  2. 从左到右搜索-L指定的目录(链接时gcc的选项)。
    后文会讲

注意

  • 系统提供的库和编译器提供的库为前两方库,其他的库被称为第三方库
  • 如果系统只提供了静态库,则gcc就只能对该库进行静态链接
  • 如果系统需要链接多个库,gcc可以链接多个的库

制作静态库

我们编写一段具有简单计算功能的代码,添加头文件,对他们进行打包

mymath.c

#include "mymath.h"int myerrno = 0;int add(int a, int b)
{return a + b;
}int sub(int a, int b)
{return a - b;
}int mul(int a, int b)
{return a*b;
}int dev(int a, int b)
{if(b == 0){myerrno = 1;return -1;}return a/b;
}

mymath.h

#pragma once
#include <stdio.h>
extern int myerrno;int add(int a, int b);int sub(int a, int b);int mul(int a, int b);int dev(int a, int b);

main.c

#include "mymath.h"int main()
{//使用静态库int n = dev(10, 0);printf("10/0 = %d, errno = %d", n, myerrno);return 0;
}

静态库的打包

具体步骤如下:

  1. 先编译源文件mymath.cmymath.o二进制文件
gcc -c mymath.c
  1. 用ar命令将.o文件打包为.a文件
ar -rc libmymath.a mymath.o
  • ar 是 GNU 提供的归档工具,常用来将目标文件打包为静态库。
  • 我们还可以使用 ar 反向查看静态库中的具体文件
    ar -tv 静态库文件在这里插入图片描述
  • -rc意指replace and create

实践中,我们通常使用makefile脚本来快速打包:

static-lib = libmymath.a$(static-lib):mymath.oar -rc $@ $^mymath.o:mymath.cgcc -c $^.PHNOY:clean 
clean:rm -rf *.o *.a mylib .PHONY:output
output:mkdir -p mylib/includemkdir -p mylib/libcp *.h mylib/includecp *.a mylib/lib

可以看到,我们通过make output还可以将头文件和库文件分门别类的拷贝一份在各自的目录里。

链接静态库

现在我们有了自己的静态库,接下来要考虑如何将它与main.c一并链接生成可执行程序了。

链接命令如下:

gcc main.c -I ./mylib/include -L ./mylib/lib -lmymath

命令解读:
1. -I [头文件路径]:前面说过,系统只会在系统默认的路径下查找头文件,因此我们头文件放在哪系统是不知道的,需要用这个选项来为系统指明位置。
2. -L [库文件路径]:与头文件类似,需要用这个选项来为系统指明库文件位置。
3. -l+库名:我们指明的只是存放库文件的目录,系统并不知道我们需要链接哪些库文件,因此需要指明具体库文件。

注意

  • -l与库名需要紧贴,不能用空格隔开
  • -l选项几乎是必用的
  • -I-L使用起来非常不爽,可以通过“安装该库”或者在系统路径下建立软链接来避免使用。

安装库文件
原理很简单,将我们制作的库文件和头文件拷贝一份到系统默认路径下即可

sudo cp mylib/include/mymath.h /usr/include
sudo cp mylib/lib/libmymath.a /lib64/

注意:

  • 系统路径在root用户下,需要sudo提权
  • 记得指明需要拷贝的具体文件
  • 安装好后,就只需用-l选项指明库文件就行了。
gcc main.c -lmymath

制作动态库

我们编写myprint.c和mylog.c方法,打印一些提示符即可。并添加相应头文件,对他们进行打包

myprint.c

#include "myprint.h"void Print()
{printf("hello linux!\n");printf("hello linux!\n");printf("hello linux!\n");printf("hello linux!\n");
}

myprint.h

#pragma once#include <stdio.h>void Print();

mylog.c

#include "mylog.h"void Log()
{printf("it is log\n");printf("it is log\n");printf("it is log\n");printf("it is log\n");
}

mylog.h

#pragma once#include <stdio.h>void Log();

main.c

#include "mymath.h"
#include "mylog.h"
#include "myprint.h"int main()
{//使用静态库int n = dev(10, 0);printf("10/0 = %d, errno = %d", n, myerrno);//使用动态库Log();Print();return 0;
}

动态库的打包

动态库的打包不像静态库一样,需要借助ar工具,他就像是gcc的亲儿子一样,gcc天然的具有动态库的打包功能,具体如下:

gcc -shared -o libmymethod.so *.o
  • -shared: 表示生成共享库格式
  • -fPIC:需要打包成动态库的源文件,编译时必须使用-fPIC选项,它表示产生位置无关码(position independent code)

比如这里的:

gcc -fPIC -c myprint.c
gcc -fPIC -c mylog.c

一样的,推荐使用makefile,我们将前面的静态库也一同打包:

dy-lib = libmymethod.so
static-lib = libmymath.a.PHNOY:all
all:$(dy-lib) $(static-lib)$(dy-lib):myprint.o mylog.ogcc -shared -o $@ $^$(static-lib):mymath.oar -rc $@ $^mymath.o:mymath.cgcc -c $^myprint.o:myprint.cgcc -fPIC -c $^mylog.o:mylog.cgcc -fPIC -c $^.PHNOY:clean 
clean:rm -rf *.o *.a *.so mylib .PHONY:output
output:mkdir -p mylib/includemkdir -p mylib/libcp *.h mylib/includecp *.a mylib/libcp *.so mylib/lib

注意这里需要完成两个任务,需要用all将二者关系独立开来。

打包后效果如下:
在这里插入图片描述

链接动态库

和静态链接一样,使用gcc编译main.c生成可执行程序时,需要用-I选项指定头文件搜索路径,用-L选项指定库文件搜索路径,最后用-l选项指明需要链接库文件路径下的哪一个库。

gcc main.c -I ./mylib/include -L ./mylib/lib -lmymethod -lmymath

但是与静态库的使用不同的是,此时我们生成的可执行程序却并不能直接运行。
在这里插入图片描述
为什么我们表明了路径还是不行呢?
可以使用ldd命令查看动态库链接情况:

ldd a.out

在这里插入图片描述

原因就是我们只是告诉了gcc这个编译器,并没有告诉系统。
而将动态库告诉系统的操作就是加载。

加载动态库

常见的加载动态库的方式有四种:

  1. 安装动态库到系统库:拷贝到系统默认的库路径/usr/lib64/
  2. 软链接动态库到系统:在系统默认的库路径/usr/lib64/下建立软链接
  3. 将自制的库文件路径添加到系统的环境变量LD_LIBRARY_PATH
  4. /etc/ld.so.conf.d建立自己的动态库路径的配置文件,然后重新ldconfig即可。

注意:实际情况下,我们使用的库一般都是别人成熟的库,都采用直接安装到系统的方式。

这里,我们也采用安装到系统的方式:

sudo cp mylib/include/myprint.h /usr/include/
sudo cp mylib/include/mylog.h /usr/include/
sudo cp mylib/include/mymath.h /usr/include/sudo cp mylib/lib/libmymethod.so /lib64/
sudo cp mylib/lib/libmymath.a /lib64/

值的一提的是:并不推荐将自己写的头文件和库文件拷贝到系统路径下,这样做会对系统文件造成污染,因此方便并不一定完美。


你有没有想过动态库是如何加载到程序的呢?
下篇文章我会结合这个问题再次谈谈进程地址空间的概念。
有错误欢迎指出,万分感谢
创作不易,三连支持一下吧~
不见不散!

http://www.dtcms.com/a/483116.html

相关文章:

  • 参透测试(1):普通权限弱口令/弱加密方式/未授权访问
  • 嘉兴专业网站排名推广网站建设的后期服务要包括什么软件
  • 统计订单总数并列出排名
  • **标题:发散创新:探索Deno框架下的应用开发之旅**摘要:本文将深入探讨Den
  • 网站icp备案新规药品网站 icp
  • Linux对象管理机制
  • 网站建设实训考试做电商的步骤
  • 微信小程序uni.request 返回值存在精度丢失问题
  • 做外贸上哪些网站鹤壁集团网站建设
  • 惠城网站建设有哪些网站建设欧美
  • 注册 区块链节点
  • 硅谷甄选(续2)首页
  • 茂名建设公司网站wordpress写书typecho主题
  • 上海网站建设软件下载唐山的做网站的企业
  • 图解网络(科普版)
  • TensorFlow Implementation of Content-Based Filtering|基于内容过滤的TensorFlow实现
  • 【Pr】Adobe Premiere Pro 2025 学习笔记-01工作流实操
  • 手机端网站模板下载开发者助手app
  • 怎样做网站代理拼多多怎么开店
  • php按步骤做网站苏州企业网站建设服务中心
  • 月报 Vol.04:新增 async test 与 async fn main 语法,新增 lexmatch 表达式
  • 04--CSS基础(3)
  • C语言--函数
  • `String`、`StringBuilder` 和 `StringBuffer`区别卓望一面面试题
  • 【11408学习记录】考研英语阅读长难句得分密码:5层拆解2016真题复杂句!
  • 网站建设启示金华网站建设团队
  • 做彩票网站代理犯法吗网站建设实施计划包括
  • 第三十五篇|日本语言学校的可计算结构:神户日语学院数据建模案例
  • 数据安全工具手册——便捷实用的安全工具集-20251014
  • 网站建设网络合同网站打开出现建设中