Linux C 制作静态库和动态库详解

9 篇文章 0 订阅
3 篇文章 0 订阅


前言

该篇主要是描述如何制作静态库和动态库,以及静态库和动态库的使用,使用gcc编译,gcc编译的基础知识请参考我这篇博客Linux gcc编译基础知识


一、静态库

静态库的文件命名:libxxx.a,对应 Windows 的 *.ib 文件

1. 制作步骤

1. 编译为 *.o 文件
2. 将 *.o 文件打包:ar rcs libCalc.a file1.o file2.o file3.0 …
3. 将头文件和库一起发布

示例如下:

[lzy@localhost Calc]$ ls
include  lib  src
[lzy@localhost Calc]$ ls include src
include:
head.h

src:
add.c  sub.c
[lzy@localhost Calc]$ cat include/head.h src/*.c
#ifndef __HEAD_H__
#define __HEAD_H__
int add(int, int);
int sub(int, int);
#endif

#include "head.h"
int add(int iNum1, int iNum2)
{
	int iResult = iNum1 + iNum2;
	return iResult;
}

#include "head.h"
int sub(int iNum1, int iNum2)
{
	int iResult = iNum1 - iNum2;
	return iResult;
}
[lzy@localhost Calc]$ cd src
[lzy@localhost src]$ gcc -c *.c -I ../include
[lzy@localhost src]$ ls
add.c  add.o  sub.c  sub.o
[lzy@localhost src]$ ar -src libCalc.a *.o
[lzy@localhost src]$ ls
add.c  add.o  libCalc.a  sub.c  sub.o
[lzy@localhost src]$ nm libCalc.a 
add.o:
0000000000000000 T add
sub.o:
0000000000000000 T sub
[lzy@localhost src]$ mv libCalc.a ../lib
[lzy@localhost src]$ ls ../lib
libCalc.a
[lzy@localhost src]$ ls ..
include  lib  src

至此,静态库打包发布已经完成,将 include 和 lib 文件夹提供给用户即可,部分参数解释如下:
ar:打包归档
-src:打包时的固定参数,不会变
libCalc.a:打包输出静态库文件名
*.o:指定要打包的 .o 文件

2. 使用静态库

废话不多说,直接上示例:

[lzy@localhost Calc]$ ls
include  lib  main.c  src
[lzy@localhost Calc]$ cat main.c 
#include <stdio.h>
#include "head.h"
int main(void)
{
	int iSum = add(6, 3);
	int iSub = sub(6, 3);
	printf("Sum = %d\n", iSum);
	printf("Sub = %d\n", iSub);
	return 0;
}
[lzy@localhost Calc]$ gcc main.c -o app -I ./include -L ./lib -lCalc
[lzy@localhost Calc]$ ./app 
Sum = 9
Sub = 3

补充说明:编译的时候,要指定头文件路径和库路径以及库名称,不然编译会报错


二、动态库

1. 制作步骤

1. 编译与位置无关的代码,生成 *.o ,关键参数 -fPIC(PIC:代码的位置无关性,可大写可小写)
2. 将 *.o 文件打包,关键参数 -shared
3. 将头文件和库一起发布

示例如下:

[lzy@localhost Calc]$ ls
include  lib  main.c  src
[lzy@localhost Calc]$ cd src/
[lzy@localhost src]$ ls
add.c  sub.c
[lzy@localhost src]$ gcc -fPIC -c *c -I ../include
[lzy@localhost src]$ ls
add.c  add.o  sub.c  sub.o
[lzy@localhost src]$ gcc -shared -o libCalc.so *.o
[lzy@localhost src]$ ls
add.c  add.o  libCalc.so  sub.c  sub.o
[lzy@localhost src]$ mv libCalc.so ../lib
[lzy@localhost lib]$ ls ../lib
libCalc.so
[lzy@localhost lib]$ cd ..
[lzy@localhost Calc]$ ls
include  lib  main.c  src

至此,动态库打包发布已经完成,将 include 和 lib 文件夹提供给用户即可,部分参数解释如下:
-fPIC:代码与位置无关
**-shared **:关键字,生成共享库
libCalc.so:打包输出动态库文件名
*.o:指定要打包的 .o 文件

2. 代码的位置无关性(PIC)

先看内存分布图:
在这里插入图片描述补充说明:如上图,静态库是保存在代码段,作为程序的一部分,函数的地址固定;而动态库作为临时加载,函数地址不固定,故编译时地址不能固定,需要编译成和位置无关的代码;对于同一个动态库,函数相对地址偏移是固定的,在加载动态库调用函数时,通过动态库所在位置加上调用函数的相对地址偏移,找到该函数的地址,然后执行该函数,所以和位置无关。

3. 使用动态库

废话不多说,直接上示例:

[lzy@localhost Calc]$ gcc main.c -o app -I ./include -L ./lib -lCalc
[lzy@localhost Calc]$ ls
app  include  lib  main.c  src
[lzy@localhost Calc]$ ./app 
./app: error while loading shared libraries: libCalc.so: cannot open shared object file: No such file or directory
[lzy@localhost Calc]$ ldd app 
	linux-vdso.so.1 =>  (0x00007ffd1436f000)
	libCalc.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f870efd4000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f870f3ab000)

哈哈,直接运行可执行环境是找不到库滴,程序只会查找系统路径或指定路径,编译时指定了所以编译过了,可以通过以下几种方法解决:

1. 将动态库 libCalc.so 拷贝到系统路径下面, /lib 或 /usr/lib(不推荐)
2. 将库路径增加到环境变量 LD_LIBRARY_PATH 中(不推荐),展示效果如下:
(1)一次生效

 [lzy@localhost Calc]$ ls
app  include  lib  main.c  src
[lzy@localhost Calc]$ echo $LD_LIBRARY_PATH

[lzy@localhost Calc]$ export LD_LIBRARY_PATH=~/Project/Calc/lib/:$LD_LIBRARY_PATH
[lzy@localhost Calc]$ ldd app 
	linux-vdso.so.1 =>  (0x00007ffcdf557000)
	libCalc.so => /home/atmuser/Project/Calc/lib/libCalc.so (0x00007fa12f935000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fa12f55f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fa12fb38000)
[lzy@localhost Calc]$ ./app 
Sum = 9
Sub = 3

(2)永久生效

 [lzy@localhost ~]$ ls -a
.              .bash_profile  .esd_auth      .local    图片     桌面
..             .bashrc        .ICEauthority  makefile  公共     文档
.bash_history  .cache         include        .mozilla  模板     下载
.bash_logout   .config        lib            Project   视频     音乐

因为开机启动的时候回加载 .bashrc 文件,所以将 export LD_LIBRARY_PATH=~/Project/Calc/lib/:$LD_LIBRARY_PATH 写到到该文件即可永久生效

3. 修改 ld.so.conf 文件(推荐),因为系统启动时会加载该文件,可在其中配置一些链接库的路径,示例如下:

 [lzy@localhost Calc]$ ls
app  include  lib  main.c  src
[lzy@localhost Calc]$ ldd app 
	linux-vdso.so.1 =>  (0x00007ffec4dfe000)
	libCalc.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007fe7c58cc000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fe7c5ca3000)
[lzy@localhost Calc]$ sudo vim /etc/ld.so.conf
[sudo] password for lzy: 
[lzy@localhost Calc]$ ldd app 
	linux-vdso.so.1 =>  (0x00007fff563e1000)
	libCalc.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f6973121000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f69734f8000)
[lzy@localhost Calc]$ sudo ldconfig 
[lzy@localhost Calc]$ ldd app 
	linux-vdso.so.1 =>  (0x00007ffdc2b35000)
	libCalc.so => /home/atmuser/Project/Calc/lib/libCalc.so (0x00007f4431955000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f4431594000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f4431b6c000)
[lzy@localhost Calc]$ ./app 
Sum = 9
Sub = 3
[atmuser@localhost Calc]$ 

补充说明:sudo 打开 /etc/ld.so.conf 文件后,在文件最下面添加一行:*.so 库的绝对路径,保存退出后,必须执行 sudo ldconfig 命令,使配置立即生效,所有命令需要管理员权限,使用sudo运行


优缺点总结

1. 静态库

优点:
1. 执行快(直接加载源码,不需要查找函数地址)
2. 发布应用是不需要发布库

缺点:
1. 执行程序体积比较大
3. 库变更时需要重新编译应用

2. 动态库

优点:
1. 执行程序体积小
2. 库变更是,一般不需要重新编译应用(如果接口修改了,需要重新编译)

缺点:
1. 执行时需要加载动态库,相对而言,比静态库慢
2. 发布应用是需要同时发布动态库

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Li_Zhi_Yao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值