C/C++ 动态库与静态库的制作和使用

3 篇文章 0 订阅

静态库的用法

静态库的文件名 libxxx.a
做静态库的命令:

ar rcs libxxx.a file1.o file2.o file.o

使用静态库:

gcc main.c -L lib/ -lxxx

注意:-L 的作用是告诉gcc你的libxxx.a放在了哪个目录里;-l 的作用是告诉gcc使用哪个静态库。
举个例子,目录结果如下:

├── include
│   └── head.h
├── lib
│   
├── main.c
└── src
    ├── add.c
    ├── mul.c
    └── sub.c

head.h

int add(int, int);
int sub(int, int);
int mul(int, int);

add.c

int add(int a, int b){
  return a + b;
}

sub.c

int sub(int a, int b){
  return a - b;
}

mul.c

int mul(int a, int b){
  return a * b;
}

步骤1:在src目录执行下面的命令,生产.o文件

gcc -c *.c   

执行后,在src目录下生产了add.o,sub.o,mul.o三个文件

步骤2:在src目录执行下面的命令,生产libCalc.a文件

ar rcs libCalc.a *.o

执行后,在src目录下生产了libCalc.a

步骤3:在src目录执行下面的命令,把libCalc.a移动到上层的lib文件夹

mv libCalc.a ../lib/

执行后,在lib文件夹出现了libCalc.a

main.c

#include <stdio.h>
#include "head.h"

int main(){
  int a = 10, b = 5;
  printf("add:%d\n",add(a, b));
  printf("sub:%d\n",sub(a, b));
  printf("mul:%d\n",mul(a, b));
}

步骤4:在src的上层目录,执行下面命令生产a.out文件

gcc main.c -I include/ -L lib/ -lCalc

-I:指定头文件所在的路径

-L:指定静态库文件所在的路径

-l:指定使用哪个静态库

最后目录结构如下:

├── a.out
├── include
│   └── head.h
├── lib
│   └── libCalc.a
├── main.c
└── src
    ├── add.c
    ├── add.o
    ├── mul.c
    ├── mul.o
    ├── sub.c
    └── sub.o

动态库的用法

动态库的文件名 libxxx.so

编译时,需要加【-fPIC】选项。

它的作用是,编译出与位置无关的代码。因为动态库在加载到下图的共享库区的时候,不一定加载到哪个位置,

所以加了-fPIC后,就记录了每个函数相对于这个动态库头地址的偏移,加载后动态库在内存里的头地址是知道的,又知道了每个函数相对于头的偏移量,自然而然地就能够找到每个函数在内存里的位置了。
在这里插入图片描述

[root@HC-25-68-165 CDynamic]# cat func.c
#include <stdio.h>
void func(void)
{
	printf("In the dynamic libbbbbb\n");
}
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# cat main.c
#include <stdio.h>
#include <unistd.h>

void func(void);

int main(void)
{
	int i = 0;
	// 为了测试在  for 循环过程中,更新 func 函数重新生成动态库,
	// 看看在不重启 main 的情况下新版 func 能否立刻生效,答案是不能!参考后面的:静态库和动态库的特点
	for(i = 0; i < 1000; i++)
	{
		printf("In the main: i = %d\n", i);
		func();
		sleep(1);
	}	
	return 0;
}
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# gcc func.c -o func.o -c -fPIC
[root@HC-25-68-165 CDynamic]# ls
func.c  func.o  main.c
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# gcc func.o -shared -o libfunc.so 
[root@HC-25-68-165 CDynamic]# ls
func.c  func.o  libfunc.so  main.c
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# 上面两句可以合并为  gcc func.c  -fPIC  -shared -o libfunc.so 
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# gcc main.c -o main -L . -l func
[root@HC-25-68-165 CDynamic]# ls
func.c  func.o  libfunc.so  main  main.c
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# ./main
./main: error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
[root@HC-25-68-165 CDynamic]# ./main 
In the main: i = 0
In the dynamic libbbbbb
In the main: i = 1
In the dynamic libbbbbb
^C
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# ldd main
linux-vdso.so.1 =>  (0x00007fff8d5ff000)
libfunc.so => ./libfunc.so (0x00007f6422533000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6422195000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6422735000)
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# 
[root@HC-25-68-165 CDynamic]# rm -fr libfunc.so 
[root@HC-25-68-165 CDynamic]# ldd main
	linux-vdso.so.1 =>  (0x00007ffff45ff000)
	libfunc.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007fbfa9c34000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fbfa9fd3000)
[root@HC-25-68-165 CDynamic]# 

对于 “ error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory”的解法方法?

办法1:把做好的动态库libCalc.so拷贝到【/lib】或者【/usr/lib】下,也可以用ln做软硬连接
      但是这种方法不推荐使用。理由是,放在了系统的动态库目录里,容易和别的库重复,发生冲突。
      也可以临时修改环境变量 LD_LIBRARY_PATH: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

办法2:告诉系统,给我加一个动态库的路径,这个是最好的办法。
      首先编辑/etc/ld.so.conf文件,添加你自己的库的路径
     然后,执行:【sudo ldconfig】,就OK了。

静态库和动态库的特点:

静态库:
    编译的时候,直接把静态库的代码直接编译到目标文件
    执行速度快,不需要在执行的时候加载动态库
    库文件修改后,必须重新编译使用库的代码
动态库
    编译的时候,不把静态库的代码直接编译到目标文件
    执行速度慢,在执行的时候需要加载动态库
    库文件修改后,一般不需要重新编译使用库的代码,只有在库的接口改变时,才需要重新编译使用库的代码。

对于动态库需要仔细理解一点:如果 ./main 启动后,把动态库 libfunc.so删除掉,那么已启动的 main 是不会报错的。
也可以理解为如果在 ./main 运行过程中,你更新了 libfunc.so 也是不会立刻生效的,需要重新启动 main 才可以。
这也是很好理解的:因为在启动 ./main 的瞬间会把动态库立刻加载到内存里,而不是 ./main 的执行过程中一直实时去检测动态库函数。

最后感谢: https://www.cnblogs.com/xiaoshiwang/p/10750141.html 和 https://blog.csdn.net/nanfeibuyi/article/details/81203021 的分享。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值