bazel 链接第三方动态库_C语言学习篇(31)——linux中制作动态链接库

引言

前面我们讲解了什么是函数库(函数库就是一些事先写好的函数集合),函数库有什么作用(可以打包我们的编写的源代码,供他人使用,同时源码不可见,保护了自己的知识产权)以及函数库有2种提供方式:静态链接库和动态链接库,前面2篇分别讲解了如何在linux中使用gcc工具链和windows中keill armcc工具链制作我们静态链接库,今天我们继续来说说如何在linux gcc制作动态链接库。

为什么不在Keil中制作动态库

我们知道动态库往往应用在多个程序运行,就单个程序而言的话,不如使用静态链接库来的效率直接,因为不管动态库还是静态库,最终都是要被加载运行的,只是动态库被加载一份,而静态库随着程序的个数重复加载。 而一般在Keil环境中开发的,多是单片机,不管是裸机还是RTOS(实时操作系统,如RT-Thread, ucosii/iii,freertos等),都是单程序运行, 因此基本上很少在单片机中使用动态库,绝大部分情况下也没必要使用。如果大家真的感兴趣可以参考下这篇文章:

https://bbs.csdn.net/topics/392392689

制作动态链接库

需要说明的在linux中动态链接库的后缀名是.so,而在Windows系统的则是.dll。好了,正式进入今天我们的主题:

第一步,老规矩还是先创建我们的.c源文件和.h头文件,在.c中实现具体的功能函数,在.h中声明这些函数,具体如下:

//创建一个test.c,简单实现了加减乘除计算//加int add(int i, int j){return (i+j);}//减int sub(int i, int j){return (i - j);}//乘int multi(int i, int j){return (i*j);}//除int div(int i, int j){if(j == 0)return -1;elsereturn (i/j);}/********************分隔符**************************///创建test.h,声明以上函数int add(int i, int j);int sub(int i, int j);int multi(int i, int j);int div(int i, int j);

第二步,只编译不链接,这里还需要编译成位置无关码(为什么要编译成位置无关码呢?这是因为我们所有的动态链接库是位置无关码,只在实际运行时,操作系统加载后才能真正确定加载的地址),具体指令:

gcc -c test.c -o test.o  -fPIC

其中:

-c 表示只编译不链接,即只生成目标文件,不生成最终的可执行文件

-o 表示指定生成文件名,如test.o

-fPIC 表示位置无关码

d7187d20afc11a33709f946a26c4d412.png

第三步,将生成得到的test.o作为材料,制作动态库,具体指令如下:

gcc test.o -o libmySync.so  -shared

其中:

libmySync.so中lib是固定的,意思为库,而后面的mySync是自定义库名,.so表示动态链接库,总结为:lib+库名.so

-shared表示制作为动态链接库,固定参数。

bcfbac549d4d5917e040d1737200e705.png

使用动态链接库

首先我们知道不管静态链接库还是动态链接库,在发布的时候需要同时发布库以及对应的.h头文件。

因此在动态链接库的目录下创建一个空目录

mkdir lib_test
7cb67761b7381b83a288376f87b5ceee.png

然后将test.h头文件拷贝到lib_test路径中(这里我们就不拷贝libmySync.so动态库了,到时候使用时指定路径即刻,因此来模拟真实使用情况),并在创建test_lib.c用来测试动态库。

d55e990223bb6897bfa005056be2919f.png
//test_lib.c内容#include "test.h"#include int main(void){printf("1 + 2 = %d.", add(1,2));printf("12 - 7 = %d.", sub(12,7));printf("23 * 3 = %d.", multi(23,3));printf("100 / 4 = %d.", div(100,4));return 0;}

接着我们尝试着编译, 与之前的静态链接库的指令同理,使用以下命令:

gcc test_lib.c -lmySync -L..

其中-lmySync中的-l(小写的L)是指定库名,即后面的mySync, -L是指定库所在的路径..是表示上一级目录。

10ac1e0eda4aabb758bd780cade60b19.png

可以看到编译无错误无警告,且生成了可执行文件a.out,接着我们尝试运行下:

61f856be15aee6e852f0d8b94149f9f4.png

发现运行时报错,根据错误提示是:无法加载我们的动态库。

我们知道这里生成的可执行文件a.out并不是完整的,一些调用函数还在动态库中,并没有实际链接到可执行文件中,虽然我们在编译时指定了库的路径,但是系统真正是将特定目录/usr/lib中的动态库加载到内存中的,因此我们需设置下,以下有两种方式:

  • 将我们的制作的动态库libmySync.so拷贝到/usr/lib下,再尝试运行a.out
sudo cp ../libmySync.so /usr/lib
6e799662d3a66d6c9503a986fb2c6a1a.png
  • 设置环境变量LD_LIBRARY_PATH, 告诉系统去加载该环境变量路径下的动态库
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/mnt/hgfs/winshare/c_test/make_dyncLib
f8c5dff4f923090a7859cada191a601a.png

这两者方式都能成功解决,个人推荐第二种,因为/usr/lib是系统路径,放着系统自带的动态库,轻易不要在这个目录下操作,以免紊乱。

总结

动态链接库与静态链接库制作过程类似,都是先要创建源文件(实现具体功能函数)和头文件(声明函数原型),接着只编译不链接源文件,生成.o目标文件(注意的是制作动态链接库时,需要使用-fPIC选项指定为位置无关码),再以.o为材料去制作我们的库:

制作静态链接库:ar -rc libmymath.a test.o

制作动态链接库: gcc test.o -o libmySync.so -shared

最后是使用库时,编译时需要指定库名和库路径,动态链接库还需要告知系统去实际加载我们动态库,因为我们可执行文件并不是完成的!而使用静态库链接的可执行文件是完整,可直接独立运行。

e8721e1d8ebcbe5104a93b3738ad4f27.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值