Linux平台下自创c函数库及库的命名约定
2021/10/2 7:12:19
本文主要是介绍Linux平台下自创c函数库及库的命名约定,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
如下所示,一段的简单到不能再简的程序:
我们可以重新查看这个小程序,在这个程序中并没有定义”printf”的函数实现,且在预编译中包含进的”stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现”printf”函数的呢?最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,Gcc会到系统默认的搜索路径”/usr/lib”下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数”printf”了,而这也就是链接的作用。
怎么能看得到自己的程序main.out是否真链接到libc.so.6库函数中去呢?linux命令“ldd”就是干这个的。(上图绿线上就是)
在linux中,大量的C库函数被封装在动态链接库“libc.so.6”中,你只需用声明其头文件,调用其C函数接口即可。通常,我们把操作系统调用接口称之为:系统API。标准C库处理调用操作系统API,处理与操作系统层打交道的复杂细节,几乎把所有的苦活累活都替你干了,完了交了一把钥匙给你。
其实,库是已经写好的、成熟的、可复用的代码。每个程序都需要依赖很多底层库,不可能每个人的代码从零开始编写,因此,库的存在具有非常重要的意义,就像C/C++库一样,不管是windows还是linux,都必不可少。
所以,不要把库看得过于高深,我们的开发的应用中经常有一些公共代码是需要反复使用的,就可以把这些代码编译为库文件,方便使用。
库有静态库和动态库之分,我们可以很简单地制作出来。前提是,我们得知道一个简易C代码的基本编译方法与步骤,就可以了。
代码:main.c ---------------------------------------------- #include <stdio.h> extern void my_lib_func_001(); extern void my_lib_func_002(); int main(void) { my_lib_func_001(); my_lib_func_002(); } 代码:f1.c --------------------------------------------- #include <stdio.h> void my_lib_func_001() { printf("This is my my_lib_func_001 ... \n"); } 代码:f2.c -------------------------------------------- #include <stdio.h> void my_lib_func_002() { printf("This is my my_lib_func_002 ... \n"); }
创建静态链接库
我们想把f1.c中的“my_lib_func_001”和f2.c中的函数"my_lib_func_002",制作一个静态库,仅需两步。。
(1)把f1.c和f2.c制作成二进制文件,生成:f1.o,f2.o
gcc -c f1.c f2.c
(2)生成静态库
ar -crv libmyStaticLib.a f1.o f2.o
"libmyStaticLib.a"生成静态函数库的名字。
(3)使用静态库
gcc main.c f1.c f2.c -o main.out
如果不使用静态库,我们可以像上面这样一行,来简单地编译输出main.out程序:
使用静态库方式,输出mainStatic.out程序,我们的编译命令如下:
gcc -o mainStatic.out main.c -static -L . -l myStaticLib
与是我们的新程序“mainStatic.out”也成功的生成了。
运行mainStatic.out :
$ ./mainStatic.out
This is my my_lib_func_001 ...
This is my my_lib_func_002 ...
说明静态链接库的编译是正确的,程序工作正常。
两个问题
这里有两个问題,在第(2)步,为什么要用"libmyStaticLib.a"作为静态函数库的名字,难道不可以用“myStaticLib.a”或者“a_sampleStaic.a”吗?
还有,既然第(2)步编译出来的静态函数库是"libmyStaticLib.a",第三步命令行中的“myStaticLib”从何而来?
好吧,我承认我也这样做过。但是编译器提示错误:“/usr/bin/ld: 找不到 -la_sampleStatic.a”
Linux库的命名约定
Linux平台上,库的命名一般是以".a"为后缀,动态库以".so"为后缀。
Linux平台上,库的命名必须如 libname.so.x.y.z格式。最前面使用前缀”lib”,中间是库的名字和后缀”.so”,最后三个数字是版本号。x是主版本号(Major Version Number),y是次版本号(Minor Version Number),z是发布版本号(Release Version Number)。
主版本号(不兼容):重大升级,不同主版本的库之间的库是不兼容的。所以如果要保证向后兼容就不能删除旧的动态库的版本。
次版本号(向下兼容): 增量升级,增加一些新的接口但保留原有接口。高次版本号的库向后兼容低次版本号的库。
发布版本号(相互兼容):库的一些诸如错误修改、性能改进等,不添加新接口,也不更改接口。主版本号和此版本号相同的前提下,不同发布版本之间完全兼容。
所以,上面的静态函数的名字"libmyStaticLib.a"不是乱起的,gcc严格遵循这个命名约定,库不以lib开头,就无法用gcc编译,而实际编译中,又要去掉lib这三个字符。编译命令“gcc -o mainStatic.out main.c -static -L . -l myStaticLib”中神奇的“myStaticLib”就是这么来的。(当然,人个测试小程序,就不要版本号xy了)
同理,下面在动态链接库创建过程中,也严格遵循这个命名约定。不仅如此,编译静态库时,还要去掉".a"后缀,编译动态库时,还要去掉".so"后缀。
创建动态链接库
(1)生成动态库
gcc -fPIC -shared -o libmyDynamicLib.so f1.c f2.c
GCC 生成动态链接库 .so 文件 (-shared 和 -fPIC 选项)
fPIC f后面跟一些编译选项,PIC是其中一种,表示生成位置无关代码(Position Independent Code),share 表示调用动态库。
(2)链接生成目标文件
gcc -o mainDynamic.out main.c -L . -l myDynamicLib
(3)拷贝动态库文件libmyDynamicLib.so
sudo cp libmyDynamicLib.so /lib/x86_64-linux-gnu/
拷贝动态库文件libmyDynamicLib.so到“/lib/x86_64-linux-gnu/“下面。
测试运行mainDynamic.out :
$ ./mainDynamic.out
This is my my_lib_func_001 ...
This is my my_lib_func_002 ...
说明动态链接的编译是正确的,程序工作正常。
这篇关于Linux平台下自创c函数库及库的命名约定的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南
- 2024-08-21【Linux】分区向左扩容的方法