Linux 静态库和动态库的生成及使用

1、分文件编程
分模块的编程思想:假设一个项目需要用到网络、超声波、电机,程序不是都杂糅在同一个文件,而是将网络、超声波、电机需要调用的函数写在不同文件里,在主文件中直接调用即可。
好处:
a.功能责任划分
b.方便调试
c.主程序简洁

2、库
使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个程序函数库简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个函数更加模块化,更容易重新编译,而且更方便升级。程序函数库可分为三种类型:静态函数库共享函数库动态加载函数库

(a)静态库
静态函数库:是在程序执行前(编译)就加入到目标程序中去。
优点:
1、静态库被打包到应用程序中加载速度快,
2、发布程序无需提供静态库,因为已经在app中,移植方便。
缺点:
1、链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝
2、更新、部署、发布麻烦

(b)动态库(动态函数库同共享函数库是一个东西,在linux上叫共享对象库,文件后缀是.so,widows上叫动态加载函数库,文件后缀是.dll)
动态函数库:是在程序执行时动态(临时)由目标程序去调用
Linux中命名系统*享库的规则
libname.so.x.y.z
固定代表共享库 共享库名称 固定后缀 主版本号 次版本号 发行版本号
优点:
1、链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序可以共用,节省内存。
2、程序升级简单,因为app里面没有动态库的源代码,升级之后只有要库的名字不变,只是实现做了优化,就能加载成功。
缺点:
1、加载速度比静态库慢
2、发布程序需要提供依赖的动态库

3、库的制作
静态库的制作 格式xxx.a
1.gcc xxx.c -c //生成xxx.o文件
2.ar rcs libxxx.a xxx.o //xxx.o文件生成xxx.a静态库文件
动态库的制作 格式xxx.so
1、gcc -shared -fpic xxx.c -o libxxx.so
-shared 指定生成动态库
-fpic 一种FPIC标准,fpic选项作用于编译阶段,在生成目标文件时就得使用该选项,以生成位置无关的代码
4、库的使用
静态库
gcc xxx.c -lxxx -L ./ -o xxx
-l是指定要用的静态库,库名开头去尾
-L 告诉gcc编译器从-L指定的路径去找静态库。默认从/usr/lib或/usr/local/lib去找
动态库
gcc xxx.c -lxxx -L ./ -o xxx
-l是指定要用的动态库,库名开头去尾
-L 告诉gcc编译器从-L指定的路径去找动态库。默认从/usr/lib或/usr/local/lib去找

接下我们来演示下静态库和动态库的生成及使用
先准备calculator.c,calcufunc.c,calcufunc.h这三个文件,calculator.c中主函数运行,调用分文件calcufunc.c中的函数。
文件calculator.c

#include <stdio.h>
#include "calcufunc.h"
int main()
{
        float a;
        float b;
        printf("please input value of a:\n");
        scanf("%f",&a);   
        printf("please input value of b:\n");
        scanf("%f",&b);
        printf("result is:\n");
        printf("%.2f+%.2f=%.2f\n",a,b,add(a,b));
        printf("%.2f-%.2f=%.2f\n",a,b,minus(a,b));
        printf("%.2f*%.2f=%.2f\n",a,b,mult(a,b));
        printf("%.2f/%.2f=%.2f\n",a,b,div(a,b));
        return 0;
}	

文件calcufunc.c

#include <stdio.h>
float add(float a,float b)
{
        return a+b;
}
float minus(float a,float b)
{
        return a-b; 
}
float mult(float a,float b)
{
        return a*b; 
}
float div(float a, float b) 
{     
        if(b==0)
        {
                return -1;
        }
        return a/b; 
}   

文件calcufunc.h

float add(float a,float b);
float minus(float a,float b);
float mult(float a,float b);
float div(float a,float b);

静态编译

//生成calcufunc.o文件
Ubuntu@Embed_Learn:~/learn/sepfile$ gcc calcufunc.c -c
Ubuntu@Embed_Learn:~/learn/sepfile$ ls
calcufunc.c  calcufunc.h  calcufunc.o  calculator.c
//生成libcalcufunc.a文件
Ubuntu@Embed_Learn:~/learn/sepfile$ ar rcs libcalcufunc.a calcufunc.o
Ubuntu@Embed_Learn:~/learn/sepfile$ ls
calcufunc.c  calcufunc.h  calcufunc.o  calculator.c  libcalcufunc.a
//移除calcufunc.c文件,没有calcufunc.c文件也可以运行MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ rm calcufunc.c
//编译:使用libcalcufunc.a静态库,当前路径查找静态库,生成MainPro可执行文件
Ubuntu@Embed_Learn:~/learn/sepfile$ gcc calculator.c -lcalcufunc -L . -o MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ls
calcufunc.h  calcufunc.o  calculator.c  libcalcufunc.a  MainPro
//执行MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ./MainPro
please input value of a:
9
please input value of b:
2
result is:
9.00+2.00=11.00
9.00-2.00=7.00
9.00*2.00=18.00
9.00/2.00=4.50

动态编译

Ubuntu@Embed_Learn:~/learn/sepfile$ ls
calcufunc.c  calcufunc.h  calculator.c
//生成动态库libcalcufunc.so
Ubuntu@Embed_Learn:~/learn/sepfile$ gcc -shared -fpic calcufunc.c -o libcalcufunc.so
Ubuntu@Embed_Learn:~/learn/sepfile$ ls
calcufunc.c  calcufunc.h  calculator.c  libcalcufunc.so
//编译:使用libcalcufunc.so动态库,当前路径查找动态库,生成MainPro可执行文件
Ubuntu@Embed_Learn:~/learn/sepfile$ gcc calculator.c -lcalcufunc -L . -o MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ls
calcufunc.c  calcufunc.h  calculator.c  libcalcufunc.so  MainPro
//执行MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ./MainPro
./MainPro: error while loading shared libraries: libcalcufunc.so: cannot open shared object file: No such file or directory

MainPro执行时,发生以上错误。因为执行时,默认从/usr/lib或/usr/local/lib路径去找动态库,没有找到。所以我们要设置指定动态库的位置,那么要怎么设置呢?
方法一:在配置文件/etc/ld.so.conf中指定动态库搜索路径。(该方法要使用管理者权限,存在一定风险)

//进入/etc路径
Ubuntu@Embed_Learn:~/learn/sepfile$ cd /etc
//编辑ld.so.conf文件
Ubuntu@Embed_Learn:/etc$ vi ld.so.conf
//文件ld.so.conf
//包含了/etc/ld.so.conf.d/路径下的所有.conf文件
include /etc/ld.so.conf.d/*.conf
[1]+  Stopped                 vi ld.so.conf
//进入/etc/ld.so.conf.d路径
Ubuntu@Embed_Learn:/etc$ cd ld.so.conf.d
Ubuntu@Embed_Learn:/etc/ld.so.conf.d$ ls
i686-linux-gnu.conf  vmware-tools-libraries.conf  x86_64-linux-gnu_GL.conf
libc.conf            x86_64-linux-gnu.conf        zz_i386-biarch-compat.conf
//编辑 libc.conff文件
Ubuntu@Embed_Learn:/etc/ld.so.conf.d$ vi libc.conf
//文件libc.conf
# libc default configuration
/usr/local/lib
[2]+  Stopped                 vi libc.conf
//创建mylibc.conf文件
Ubuntu@Embed_Learn:/etc/ld.so.conf.d$ sudo touch mylibc.conf
//编辑mylibc.conf文件
Ubuntu@Embed_Learn:/etc/ld.so.conf.d$ sudo vi mylibc.conf
//文件mylibc.conf
/home/Ubuntu/learn/sepfile
[3]+  Stopped                 sudo vi mylibc.conf
//回到/home/Ubuntu/learn/sepfile路径
Ubuntu@Embed_Learn:/etc/ld.so.conf.d$ cd /home/Ubuntu/learn/sepfile
//执行MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ./MainPro
please input value of a:
9
please input value of b:
2
result is:
9.00+2.00=11.00
9.00-2.00=7.00
9.00*2.00=18.00
9.00/2.00=4.50

方法二:通过环境变量LD_LIBRARY_PATH指定动态库搜索路径。

export LD_LIBRARY_PATH=”path” 
//查询当前路径
Ubuntu@Embed_Learn:~/learn/sepfile$ pwd
/home/Ubuntu/learn/sepfile
//将当前路径添加到环境变量LD_LIBRARY_PATH中
Ubuntu@Embed_Learn:~/learn/sepfile$ export LD_LIBRARY_PATH="/home/Ubuntu/learn/sepfile"
//执行MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ./MainPro
please input value of a:
9
please input value of b:
2
result is:
9.00+2.00=11.00
9.00-2.00=7.00
9.00*2.00=18.00
9.00/2.00=4.50

为了执行MainPro更加便捷,我们可以使用脚本文件。

//创建lib.sh脚本文件
Ubuntu@Embed_Learn:~/learn/sepfile$ touch lib.sh
//编辑lib.sh脚本文件
Ubuntu@Embed_Learn:~/learn/sepfile$ vi lib.sh
//lib.sh脚本文件添加可执行权限
Ubuntu@Embed_Learn:~/learn/sepfile$ chmod +x lib.sh
//文件lib.sh
export LD_LIBRARY_PATH="/home/Ubuntu/learn/sepfile"
./MainPro
//执行lib.sh脚本文件
Ubuntu@Embed_Learn:~/learn/sepfile$ ./lib.sh
please input value of a:
9
please input value of b:
2
result is:
9.00+2.00=11.00
9.00-2.00=7.00
9.00*2.00=18.00
9.00/2.00=4.50

方法三:在编译目标代码时指定该程序的动态库搜索路径。
可以在编译目标代码时指定程序的动态库搜索路径。通过gcc 的参数”-Wl,-rpath=path”指定。

Ubuntu@Embed_Learn:~/learn/sepfile$ gcc calculator.c -lcalcufunc -L . -Wl,-rpath=/home/Ubuntu/learn/sepfile -o MainPro
Ubuntu@Embed_Learn:~/learn/sepfile$ ./MainPro
please input value of a:
7
please input value of b:
2
result is:
7.00+2.00=9.00
7.00-2.00=5.00
7.00*2.00=14.00
7.00/2.00=3.50
上一篇:稀疏sparse array数组


下一篇:NLP(三十三):中文BERT字字量