Linux中gcc创建与使用静态库和动态库

一. 关于库的定义

1. 库.
  • 库是写好的,现有的,成熟的,可以复用的代码,本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
  • 库分为静态库和动态库。
2. 静态库(.a)
  • 静态库在程序编译时会被连接到目标代码中去,与汇编生成的目标文件.o一起链接打包到可执行文件中,因此程序运行时不再需要该静态库
  • 一个静态库可以看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件
3. 动态库(.so)
  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入
  • 不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题

二. gcc生成静态库和动态库

1. 编辑生成子程序hello.h、hello.c和main.c
  • 首先创建一个目录,保存本次练习的文件test1

  • Documents中右键点击Open in Terminal打开终端
    在这里插入图片描述

  • 输入以下命令

 mkdir test1         //创建一个名为test1的目录 
 cd test1           //切换工作目录为test1

在这里插入图片描述

  • 创建好后在Documents中发现多了一个test1的文件夹,如下图
    在这里插入图片描述
  • Documents中打开终端
  • 输入cd test1命令,使工作目录切换到test1目录
  • 然后分别输入touch hello.htouch hello.ctouch main.c命令创建三个文件
    在这里插入图片描述
  • 输入nano命令打开hello.h文件
nano hello.h
  • 写入hello.h的代码,然后”ctrl s“保存,如下图
    在这里插入图片描述
  • 输入nano命令打开hello.c文件
nano hello.c
  • 写入hello.c的代码,然后”ctrl s“保存,如下图
    在这里插入图片描述

  • 输入nano命令打开main.c文件

nano main.c
  • 写入main.c的代码,然后”ctrl s“保存,如下图
    在这里插入图片描述
2. 将hello.c编译成.o文件
  • test1目录中打开终端,然后输入gcc -c hello.c命令得到hello.o文件,并运行ls命令观察是否生成了hello.o文件
    在这里插入图片描述
3. 由.o文件创建静态库
  • test1目录中打开终端,然后输入ar -crv libmyhello.a.hello.o命令得到libmyhello.a文件,并运行ls命令观察是否生成了libmyhello.a文件
    在这里插入图片描述
4. 在程序中使用静态库
(1)生成目标程序hello,使静态库可以在程序中使用
方法一
  • test1目录中打开终端,输入gcc -o hello main.c -L. -lmyhello命令
方法二
  • test1目录中打开终端,输入gcc main.c libmyhello.a -o hello命令
方法三
  • test1目录中打开终端,首先输入gcc -c main.c命令生成main.o
  • 然后输入命令gcc -o hello main.o libmyhello.a生成可执行文件

我们采用方法一生成目标程序hello,如下图所示

在这里插入图片描述

(2)执行hello文件
  • 打开终端,输入./hello指令,验证其是否能够正常运行
    在这里插入图片描述
    如图显示Hello everyone!,运行成功
  • 输入指令rm libmyhello.a,移除静态库后,再次运行hello,验证静态库中的公用函数是否已经全部连接到目标文件中去
    在这里插入图片描述
    移除静态库后,目标文件仍然能够正常运行,说明静态库中的公用函数是否已经全部连接到目标文件中去
5. 由.o文件创建动态库文件

动态库文件名命名规范和静态库文件名命名规范类似,但其文件扩展名为.so

  • test1目录中打开终端,输入gcc -shared -fPIC -o libmyhello.so hello.o命令得到libmyhello.so文件,并运行ls命令观察是否生成了libmyhello.so文件
    在这里插入图片描述
6. 在程序中使用动态库
(1)生成目标文件hello,使动态库可以在程序中使用

在程序中使用动态库和使用静态库完全一样

  • test1目录中打开终端,输入gcc main.c libmyhello.so -o hello命令生成目标文件hello
    在这里插入图片描述
(2)执行hello文件
  • 打开终端,输入./hello指令,验证连接是否成功
    在这里插入图片描述
    发现报错,原来是找不到动态库文件libmyhello.so,因为连接时用的是当前目录的动态库,但程序在运行时,是在/usr/lib 目录中查找需要的动态库文件
  • 解决办法:将文件libmyhello.so复制到目录/usr/lib中,然后输入指令mv libmyhello.so /usr/lib运行
    在这里插入图片描述
    发现不能将文件libmyhello.so复制到目录/usr/lib中,提示Permisson denied,原因是权限不足,上网查找解决办法如下
  • 输入命令sudo passwd
  • 提示你输入新密码,再次输入密码成功后,输入su root
  • 最后再次输入密码后拷贝文件成功
  • 再次输入mv libmyhello.so /usr/lib,然后输入./hello指令,运行成功!
    在这里插入图片描述

补充:生成动态库的三种方式

(1)把库拷贝到/usr/lib/lib目录下
(2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径
例如动态库 libhello.so/home/example/lib 目录下:
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/example/lib
(3)修改/etc/ld.so.conf 文件,把库所在的路径加到文件末尾,并执行 ldconfig 刷新。这样加入的目录下的所有库文件都可见

7.分析静态库和动态库

思考:当静态库和动态库同名时,gcc命令会使用哪个库文件呢?

(1)删除.c和.h外的所有文件,恢复我们刚刚编译完举例程序状态

  • 输入命令rm -f hello hello.o /usr/lib/libmyhello.so删除.c和.h外的所有文件
  • 然后运行ls命令显示此时目录中的所有文件
    在这里插入图片描述
    (2)输入下列命令创建静态库文件libhello.a和动态库文件libhello.so
    在这里插入图片描述

(3)使用函数库hello生成目标文件hello并运行

  • 生成目标文件hello
    在这里插入图片描述
  • 运行程序hello
    在这里插入图片描述
    运行报错,说明当静态库和动态库同名时,gcc 命令将优先使用动态库,默认去连接/usr/lib中的动态库,将文件libhello.so复制到目录/usr/lib可解决该问题

三. 编译参数解析

命令解析
-shared指定生成动态连接库
-fPIC表示编译为位置独立的代码,达到代码的真正共享
-L.表示要连接的库在当前的目录中
-l链接文件。用-l的方式指定库名时, 会自动添加lib前缀 及.a/.so后缀
LD_LIBRARY_PATH这个环境变量指示动态连接器可以装载动态库的路径,如果有 root 权限的话,可以修改/etc/ld.so.conf 文件,然后调用 /sbin/ldconfig 来达到;如果没有 root 权限,只能采用输出 LD_LIBRARY_PATH 的方法
ldd列出动态库依赖关系

调用动态库的时候会经常碰到,明明已经将库的头文件所在目录 通过 “-I”include 进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过 ldd 命令察看时,却找不到指定链接的 so 文件,这时要通过修改LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录,就能解决库无法链接的问题

四. 实例

详细过程参照hello程序过程

实例一

1. 创建作业目录并生成所需文件
  • 创建一个test2目录,然后创建四个文件A1.c、A2.c、A.h、test.c
    在这里插入图片描述
2. 写入代码
/*A1.c*/
#include<stdio.h>
void print1(int arg)
{
	printf("A1 print arg:%d\n",arg);
}
/*A2.c*/
#include<stdio.h>
void print2(char *arg)
{
	printf("A2 printf arg:%s\n",arg);
}
/*A.h*/
#ifndef A_H
#define A_H
void print1(int);
void print2(char *);
#endif
/*test.c*/
#include<stdio.h>
#include"A.h"
int main()
{
	print1(1);
	print2("test");
	exit(0);
}
3. 静态库.a文件的生成与使用

在这里插入图片描述

4. 动态库.so文件的生成与使用

在这里插入图片描述

  • 同时也可以使用gcc -o test test.c -L. -lname来使用相应库文件,其中
    -L:表示在当前目录下,可自行定义路径path,即使用-Lpath
    -lname:name表示对应库文件的名字(除开lib),即若使用libafile.a,则name为afile;若要使用libsofile.so,则name为sofile

实例二

详细过程参照hello程序过程

1. 创建作业目录并生成所需文件
  • 创建一个test3目录,然后创建四个文件sub1.c、sub2.c、sub.h、main.c
    在这里插入图片描述
2. 写入代码
  • touch命令创建文件,nano命令打开文件,然后写入代码
    在这里插入图片描述
/*sub1.c*/
float x2x(int x,int y)
{
	float r;
	r=x+y;
	return r;
}
/*sub2.c*/
float x2x(int x,int y)
{
	float r;
	r=x*y;
	return r;
}
/*sub.h*/
#ifndef SUB_H
#define SUB_H
float x2x(int x,int y);
float x2y(int x,int y);
#endif
/*main.c*/
#include<stdio.h>
#include"sub.h"
int main()
{
    int x,y;
    x=2;
    y=3;
    printf("x+y=%f\n",x2x(x,y));
    printf("x*y=%f\n",x2y(x,y));
    return 0;
}
3. 静态库.a文件的生成与使用

在这里插入图片描述

4. 动态库.so文件的生成与使用

在这里插入图片描述

五. 总结

做完整个过程后,发现静态库和动态库的生成与使用其实还是比较容易的,静态库在运行可执行文件时,静态库是在可执行文件内部,即使删除静态库后程序还是能够运行,而动态库在运行可执行文件时,可执行文件需要与动态库相链接起来才能运行,所以当动态库被删除后程序无法运行,这就是静态库和动态库的区别~文章仅供参考,若有纰漏之处,欢迎大家斧正(●’◡’●)

参考文献

gcc生成静态库.a和动态库.so
Linux下出现permission denied的解决办法
静态库 - 百度百科

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值