当前位置: 首页 > 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/484171.html

相关文章:

  • 上饶专业的企业网站建设公司建设电影网站论文
  • 混合精度参数说明及数据集相关参数(121)
  • 网站建设前期规划中学生做的网站有哪些
  • 滨州网站建设哪家好空气炸锅做糕点的网站
  • 广州网站设计公司推荐哪家落地页网站建设
  • discuz网站编码戚墅堰网站建设
  • 电子商务网站设计与规划网站建设工作情况
  • 唐山网站制作价格做网站用什么软件?
  • 【04】C#入门到精通——C# 程序错误处理, try catch 捕获异常,避免程序崩溃
  • 学校建设网站目标东营网站建设那家好
  • 上市公司网站建设分析评价wordpress前台注册登录弹窗代码
  • 站长平台工具淮南电商网站建设价格
  • ST_7735S TFT屏幕驱动移植 (at32f421c8t7)
  • 网站留言短信通知 源码wordpress 网页搜索排名
  • 主营网站建设会计记账产品推广软文范文
  • 手机上网网站建设wordpress+判断标签
  • 网站设计是做什么的wordpress淘宝客网站模板
  • 微信做购物网站怎么抽佣wordpress官方模板下载
  • 我的网站是面向全国的选哪个公司的服务器比较好手机wap网站建设解决方案
  • 网上接网站做唐山市住房和诚乡建设局网站
  • 南宁专业做网站高水平的郑州网站建设
  • 聊天室项目开发——说明开发环境,安装并使用第一个第三方库gflags
  • 如何建设个人免费网站教程视频自己做动漫头像的网站
  • 旅行社网站建设方案书创新能力建设资金网站
  • 电子电气架构 --- 车载操作系统鸿蒙OS和AliOS
  • 网站建设怎么做帐门户模板
  • 网站在阿里云备案福田响应式网站建设服务
  • 广东h5网站建设phpcms 手机网站
  • 论坛网站源码下载网站建设与维护的案例
  • 长沙建网站理温州电商网站建设