使用 gcc 生成 .a 静态库和 .so 动态库

2023-02-05 08:48:12

一、通过gcc生成静态库和动态库

(一)创建生成例子程序

首先创建对应的test1目标目录,使用vim生成序 hello.h、hello.c 和 main.c文件

生成test1目录并跳转到该目录下
在这里插入图片描述
程序hello.h

#ifndef HELLO_H 
#define HELLO_H 
void hello(const char *name); 
#endif //HELLO_H

程序hello.c

#include <stdio.h> 
void hello(const char *name) 
{
	printf("Hello %s!\n", name); 
}

程序main.c

#include "hello.h" 
int main() 
{
	hello("everyone");
	return 0; 
}

(二)静态库

1.将 hello.c 编译成.o 文件

无论是静态库还是动态库都是由.o文件创建,所以我们需要先使用gcc将hello.c编译成.o文件
生成hello.o命令:

gcc -c hello.c

查看是否生成成功
在这里插入图片描述
可以看到该目录下已经生成了hello.o文件

2.用生成的.o文件创建静态库

静态库的命名规范是使用lib为前缀,后面跟静态库名称,扩展名为.a。所以将本次的静态库名称命名为libhello.a
使用ar命令创建我们的libhello.a静态库文件

ar -crv libhello.a hello.a

使用ls命令查看是否生成成功
在这里插入图片描述
可以看到libhello.a生成成功

3.在程序中使用静态库

如何使用静态库内部函数?只需要在使用到这些公用函数的源程序中包 含这些公用函数的原型声明,在gcc生成目标文件时指明对应的静态库,gcc 将会从 静态库中将公用函数连接到目标文件中

main.c 中,我们包含了静态库的头文件 hello.h,然后在主程序 main 中直接调用 公用函数 hello,生成hello文件然后运行查看结果
方法一:
将 -L. 放在main.c和-lhello之间,注意不能将 -L. 放在-lhello后

gcc -o hello main.c -L. -lhello

解释:

L. 表示要连接的库在当前目录中;(多个库:在编译命令行中,将使用的静态库文件放在 源文件后面就可以了。比如: gcc -L/usr/lib myprop.c libtest.a libX11.a libpthread.a -o myprop 其中-L/usr/lib 指定库文件的查找路径。编译器默认在当前目录下先查找指定的库文件

查看结果:
在这里插入图片描述
方法二:

gcc main.c libhello.a -o hello

方法三:
先生成main.o文件

gcc -c main.c

在生成可执行文件

gcc -o hello hello.o libhello.a

(二)动态库

1.用生成的.o文件创建动态库

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib,但其 文件扩展名为.so,例如我们要创建的动态库名为hello,则动态库文件名为libhello.so

使用gcc命令创建动态库文件

gcc -shared -fPIC -o libhello.so hello.o

解释:

-shared 该选项指定生成动态连接库(让连接器生成 T 类型的导出符号表,有时候也生成 弱连接 W 类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。
-fPIC 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载 入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

使用ls查看是否生成成功
在这里插入图片描述
可以看到libhello.so生成成功

2.在程序中使用动态库

程序中使用动态库和使用静态库完全一样,但是需要注意的是程序运行时调用动态库是在/usr/lib目录下寻找的,所以我们需要将动态库文件复制到目录/usr/lib下:

在管理员权限下用mv命令将libhello.so复制到/usr/lib目录下

sudo mv libhello.so /usr/lib

再cd到该目录下查看是否含有该文件
在这里插入图片描述
可以看到已经将libhello.so复制到/usr/lib下

我们再使用gcc命令链接hello动态库重新生成hello1可执行文件

gcc -o hello1 main.c -L. -lhello

查看结果
在这里插入图片描述
可以看到hello1可执行文件成功生成并运行

(三)思考

静态库和使用动态库编译成目标程序使用的 gcc 命令完全一样, 那当静态库和动态库同名时,gcc 命令会使用哪个库文件呢?

我们为了测试将生成的执行文件和usr/lib目录下的动态库删除重新移动到当前test1目录下,由于动态库文件没有在/usr/lib目录下,如果重新生成hello可执行文件,如果提示错误那么就是优先调用动态库,反之就是优先调用静态库。

首先使用rm命令删除可执行文件
在这里插入图片描述
再cd到目录/usr/lib下将libhello.so移动回test1目录下
在这里插入图片描述
可以看到相关文件都已经准备好了,接下来使用gcc命令创建可执行文件

gcc -o hello main.c -L. -lhello

运行hello文件
在这里插入图片描述

可以看到发生错误,没有连接到到对应的库,所以可以认为当静态库和动态库名称一样时优先调用动态库

(四)实例使用静态库

经过上面讲解,让我们重新创建一个例子熟悉一下静态库的创建和使用吧!
具体要求:
创建一个x2x函数,x2y函数以及main函数,将这3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小。

首先创建对应文件
x2x.c

#include <stdio.h>
int x2x(int x)
{
	return x*x;
}

x2y.c

#include <stdio.h>
int x2y(int x,int y)
{
	return x*y;
}

x2x.h

#ifndef X2X_H
#define X2X_H
int x2x(int x);
#endif

x2y.h

#ifndef X2Y_H
#define X2Y_H
int x2y(int x,int y);
#endif

main.c

#include <stdio.h>
#include "x2x.h"
#include "x2y.h"
void main()
{
	int x,y;
	printf("Please input the value of x:");
	scanf("%d",&x);
	printf("Please input the value of y:");
	scanf("%d",&y);
	printf("x*x=%d\n",x2x(x));
	printf("x*y=%d\n",x2y(x,y));
}

用gcc分别编译为3个.o 目标文件

gcc -c main.c x2x.c x2y.c

在这里插入图片描述
相关.o文件生成成功
接下来使用ar命令生成静态库

ar crv libmultip.a x2x.o x2y.o

在这里插入图片描述
连接静态库生成可执行文件

gcc -o multip1 main.c -L. -lmultip

使用命令ls查看可执行文件大小

ls -lh multip1

在这里插入图片描述
可以看到文件大小为7.4k

(五)实例使用动态库

利用上面生成的.o文件创建一个动态库

gcc -shared -fPIC -o libmultip.so x2x.o x2y.o

在这里插入图片描述
利用动态库创建可执行文件

gcc main.c libmultip.so -o multip2

在这里插入图片描述

可以看到动态库生成可执行文件为7492B而静态库生成的可执行文件为7528B;动态库.so文件大小为6888B,静态库.a文件大小为1936B。
所以可以得出结论:
通过比较发现静态库要比动态库要小很多,生成的可执行文件大小也存在较小的差别。

  • 作者:-45°
  • 原文链接:https://blog.csdn.net/qq_52187415/article/details/126861237
    更新时间:2023-02-05 08:48:12