前言:要学习linux底下的库,那么我们肯定是先要了解到底什么是库?
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行,就是将源代码转变成二进制格式的源代码,这就是相当于是对这部分的代码进行了加密,别人可以使用这个库,但是看不见库里面的内容。
库也叫程序函数库,那么使用库的好处是什么呢,其实跟上一节的分文件编程的思想是几乎是一样的。
程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。
一、库的分类
静态函数库(static libraries),共享函数库(shared libraries),
动态加载函数库(dynamically loaded libraries)
由于共享函数库也叫动态加载函数库,所以在本文只介绍静态函数库和动态加载函数库
二、库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
现在少用静态库,多用动态库,但有些场景也会用到静态库。
三、库的详解
a. 静态库
静态函数库:是在目标程序执行前(编译的时候)就加入到目标程序中去了。
优点:
1)静态库在编译的时候就被打包到应用程序中,所以其加载的速度快
2)发布程序的时候无需提供静态库,因为已经在app中,移植方便
缺点:
1)链接时完整的拷贝到可执行文件中,被多次使用就会有多份冗余拷贝
2) 更新,部署,发布麻烦
b. 动态库
动态加载函数库:是在目标程序执行时动态(临时)由目标程序去调用
优点:
1)链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序可以共用,节省内存
2)程序升级简单,因为app中没有库的源代码,升级之后只要库的名字不变,函数名与及参数不变,只是做了优化,就能加载成功
缺点:
1)加载速度比静态库慢
2)发布程序时需要提供依赖的动态库
四、库的制作与使用
a. 静态库的制作和使用
(1)命名的规则
静态库文件名的命名方式是“libxxxxx.a”
,库名前加“lib”
,后缀用“.a”
,“xxxxx”
为静态库的真实名字
(2)制作的步骤
原材料:.c
或.cpp
文件
a. 首先将.c
文件生成.o
文件,通过 gcc xxxx.c -c
生成
b. 将.o
文件进行打包成后缀为.a
的静态库文件
通过 ar rcs libxxx.a xxx.o
的方式进行打包
(3)静态库的使用
gcc calculator.c -lmystatic -L ./ -o mainSatic
-l
(小写的L
):指定要用的静态库,库名要看头去尾(即要去掉lib
和后缀.a
),(-lmystatic)
-L
(大写的L
):告诉gcc
编译器从-L
指定的路径去找静态库,如果没有指定,则默认从/usr/lib
或/usr/local/lib
去找 ,则这里有指定./
,-L ./
的意思就是从当前路径去找
-o
(小写的O
):指定生成的可执行文件
运行:直接像我们平时运行一样./mainStatic
b. 动态库的制作和使用
(1)命名规则
动态库的命名方式静态库的命名方式相似,前缀一样,都为“lib”
,静态库的后缀是.a
,而动态库的后缀变成.so
(2)制作步骤
原材料:.c
或.cpp
文件
a.首先将.c
文件生成.o
文件(需要加一个参数-fpic
),通过gcc xxx.c -c -fpic
来生成
b.将.o
文件打包成后缀为.so
动态库文件,通过 gcc -shared xxx.o -o libxxx.so
进行打包
c.其实是可以将上述两个步骤合成一个步骤来完成的,通过gcc -shared -fpic xxx.c -o libxxx.so
来跳过第一个步骤直接生成.so
文件
-fpic
:使用 -fPIC
选项,会生成 PIC
代码。.so
要求为 PIC
,以达到动态链接的目的,否则,无法实现动态链接
-shared:
指定生成动态库
(3)动态库的使用
gcc calculator.c -lmyDy -L ./ -o mianDy
-l
(小写的L
),-L
(大写的L
),-o
(小写的O
),这几个参数在静态库的使用那里已经有,动态库跟静态库是一模一样的
动态库的运行:
这里要注意了,动态库跟静态库的运行不一样,如果还是像静态库一样用./mainDy
的方式来进行运行的话是会报错的, No such file or directory
这里要回到静态库跟动态库的区别,静态库是在程序编译的时候就加到目标程序中去,而动态库是在目标程序在执行的时候由目标程序临时的去调用
(4)动态库的指定位置的搜索
在这里主要介绍两个方法,其实方法有很多
方法一:通过环境变量LD_LIBRARY_PATH
指定动态库搜索路径
方法二:在编译目标代码时指定该程序的动态库搜索路径
方法一:
export LD_LIBRARY_PATH=”/home/CLC/test/Dylib”
双引号里的位置就是动态库所在的目录,我的是在/home/CLC/test/Dylib
底下
执行上面的语句通过环境变量的方法来指定动态库的位置,但是这样有一点是不好的就是这个方法是一次性的,再打开另一个终端界面再执行./mainDy
就会重复提示刚开始的那种错误No such file or directory
如果想用这种方式,那么也有一个办法,那就是写一个shell脚本文件来执行这个程序,
将环境变量的内容跟可执行文件同时放进这个脚本里
mystart
.sh
export LD_LIBRARY_PATH="/home/CLC/test/Dylib"
./mainDy
由于shell脚本是没有可执行权限的,所以要进行一下操作
chmod +x mystart.sh
x
是可执行的意思,之后再任何一个终端界面我们都可以通过直接运行(./mystart.sh
)这个脚本文件来运行目标程序.
方法二:
可以在编译目标代码时指定程序的动态库搜索路径。通过gcc
的参数”-Wl,-rpath”
指定
这个方法可以避免安装部署的麻烦
举例说明:
有calculator.c,calculatorfun.c,calculatorfun.h
,其中calculator.c调用文件calculatorfun.c 所生成的动态库
a. gcc -shared -fpic calculatorfun.c -o libmyDy.so
,一步到位生成动态库
b. 编译calculator.c
,链接并指定运行时动态库libmyDy.so
的位置
编译如下,运行就像./mainDy
这样就行了
gcc calculator.c -lmyDy -L ./ -Wl,-rpath=./ -o mainDy
亲测了一下,这个方法是永久的,所以建议使用方法二
动态库指定位置优秀博文参考
(5)静态库的使用示例
calculator.c calculatorfun.c calculatorfun.h calculatorfun.o libmystatic.a mainSatic
以上就是静态库相关的所有文件
calculator
.c
#include <stdlib.h>
#include <stdio.h>
#include "calculatorfun.h"
int main(){
char suanfa;
int a;
int b;
int mark = 0;
int cnt = 0;
printf("Please input the a\n");
scanf("%d",&a);
printf("Please input the b\n");
scanf("%d",&b);
printf("Please choose the suanfa\n");
getchar();
scanf("%c",&suanfa);
tips(suanfa);
while(1){
cnt++;
xuansuanfa(a,b,suanfa);
if(cnt=5){
break;
}
}
return 0;
}
calculatorfun
.c
#include<stdlib.h>
#include<stdio.h>
int add(int x,int y){
int z;
z = x+y;
return z;
}
int min(int x,int y){
int z;
z = x-y;
return z;
}
int mul(int x, int y){
int z;
z = x*y;
return z;
}
float chufa(int x, int y){
int z;
z = (float)x/y;
return z;
}
void tips(char suanfa){
switch(suanfa){
case'+':
printf("you input +\n");
break;
case'-':
printf("you input -\n");
break;
case'*':
printf("you input *\n");
break;
case'/':
printf("you input /\n");
break;
default:
printf("sorry,you input errror\n");
break;
}
}
void xuansuanfa(int a,int b,char suanfa){
switch(suanfa){
case'+':
printf("The sum of the two data is %d\n",add(a,b));
break;
case'-':
printf("The min of the two data is %d\n",min(a,b));
break;
case'*':
printf("The mul of the two data is %d\n",mul(a,b));
break;
case'/':
printf("The chufa of the two data is %f\n",chufa(a,b));
break;
}
}
calculatorfun
.h
int add(int x,int y);
int min(int x,int y);
int mul(int x, int y);
float chufa(int x, int y);
void tips(char suanfa);
void xuansuanfa(int a,int b,char suanfa);
编译:gcc calculator.c -lmystatic -L ./ -o mainStatic
运行:./mainStatic
(6)动态库使用示例
calculator.c calculatorfun.c calculatorfun.h calculatorfun.o libmyDy.so mainDy mystart.sh
前三个文件在静态库的使用示例里
mystart.sh
export LD_LIBRARY_PATH="/home/CLC/test/Dylib"
./mainDy
编译:
方法一:gcc calculator.c -lmyDy -L ./ -o mainDy
运行:./mystart.sh
(这步切记要对mystart.sh
赋予可执行的权限)
编译
方法二:gcc calculator.c -lmyDy -L ./ -Wl,-rpath=./ -o mainDy
运行:./mainDy
以上就是对linux
库的相关操作的学习
学习笔记,仅供参考