Ubuntu 20.04 下用 gcc 生成 .a 静态库和 .so 动态库

1 用 gcc 生成静态库和动态库

1.1 前言

我们通常把一些公用函数制作成函数库,供其它程序使用。 函数库分为静态库动态库两种。
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

1.2 Holle 实例说明

1.2.1 准备 hello 代码

第一步:创建一个目录
创建一个文件夹 test1 用来储存 C 文件,保存本次练习的文件。

mkdir test1
cd test1

在这里插入图片描述

第二步:编写 hello 的 .h、.c 文件,及 main.c

使用 nano 编辑器,编写三个文件。

可以输入命令:sudo apt install nano 进行安装。
代码编写完成后,点击Ctrl+x,然后提示Y/N是否保存写入,输入Y即可,在按Enter确认。

在这里插入图片描述
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;
}

第三步:将 hello.c 编译成 .o 文件。
无论静态库,还是动态库,都是由 .o 文件创建的。
在系统提示符下键入命令:gcc -c hello.c得到 hello.o 文件。
并运行 ls 命令看看是否生存了 hello.o 文件。
在这里插入图片描述
生成了 hello.o 文件,本步操作完成。

1.2.2 生成 .a 静态库文件

第一步:由 .o 文件创建静态库

静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为 .a。

创建静态库用 ar 命令。
在系统提示符下键入命令:ar -crv libmyhello.a hello.o将创建静态库文件libmyhello.a。
在这里插入图片描述
可以看见有了一个 libafile.a 静态库文件了。

第二步:在程序中使用静态库
在用 gcc 命令生成目标文件时指明静态库名,gcc 将会从静态库中将公用函数连接到目标文件中。

  • 方法一:gcc -o hello main.c -L. -lmyhello

在这里插入图片描述

自定义的库时,main.c 还可放在-L.和 –lmyhello 之间,但是不能放在它俩之后,否则会提示 myhello没定义,但是是系统的库时,如 g++ -o main(-L/usr/lib) -lpthread main.cpp 就不出错。

  • 方法二:gcc main.c libmyhello.a -o hello

  • 方法三:
    先生成main.o :gcc -c main.c
    再生成可执行文件:gcc -o hello main.o

  • 执行结果:
    在这里插入图片描述

  • 静态库的特点

删掉静态库的情况下,运行可执行文件,发现程序仍旧正常运行,表明静态库跟程序执行没有联系。同时,也表明静态库是在程序编译的时候被连接到代码中的。

键入命令:rm -f libafile.a test即可删除。
在这里插入图片描述

1.2.3 生成 .so 动态库文件

第一步:创建动态库文件

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib,但其文件扩展名为 .so。

用 gcc 来创建动态库。
在系统提示符下键入命令:gcc -shared -fPIC -o libmyhello.so hello.o (-o 不可少),得到动态库文件 libmyhello.so。
在这里插入图片描述
使用 ls 命令可以发现此时动态库文件生成。

第二步:在程序中使用动态库(链接动态库文件)
用 gcc 命令生成目标文件时指明动态库名进行编译,
键入命令:gcc -o hello main.c -L. -lmyhellogcc main.c libmyhello.so -o hello
再键入命令:./hello运行可执行文件hello,这时会出现错误。
在这里插入图片描述
是因为虽然连接时用的是当前目录的动态库,但是运行时,是到 /usr/lib 中找库文件的。
解决方法:键入命令:mv libmyhello.so /usr/lib,将文件 libmyhello.so 复制到目录 /usr/lib 中就 OK 了。
在这里插入图片描述

注意:可以用 sudo 解决权限问题

1.2.4 小结

从程序 hello 运行的结果中很容易知道,当静态库和动态库同名时,gcc 命令将优先使用动态库,默认去连 /usr/lib 和 /lib 等目录中的动态库,将文件 libmyhello.so 复制到目录 /usr/lib 中即可。

1.3 实例使用库

此处过程与上述 hello 程序过程类似,不再过多赘述

1.3.1 准备代码

第一步:创建新的目录
分别键入:

mkdir test12
cd test12

在这里插入图片描述
第二步:编写4个 c语言文件
使用 nano 编辑器,编写四个文件。
在这里插入图片描述
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);
}

第三步:将三个 .c文件编译成三个 .o 文件。
分别键入:

gcc -c A1.c A2.c
ls

在这里插入图片描述
可见已经有个三个 .o 文件。

1.3.2 生成 .a 静态库文件

第一步:由 .o 文件创建静态库
分别键入:

ar -crv libafile.a A1.o A2.o
ls

在这里插入图片描述
可见已有一个 libafile.a 静态库文件。
第二步:在程序中使用静态库
键入:

gcc -o test test.c -L. -lafile

在这里插入图片描述
错误解决方式:将 test.c 中的exit(0)修改为return 0
执行结果:
键入:

./test

在这里插入图片描述

1.3.3 生成 .so 动态库文件

第一步:创建动态库文件

  • 删除静态库文件和可执行文件,只保留目标文件

分别键入:

rm libafile.a
ls

在这里插入图片描述

  • 在系统提示符下键入命令:gcc -shared -fpic -o libsofile.so A1.o A2.o (-o不可少),得到动态库文件 libsofile.so。

在这里插入图片描述
可见,生成了动态库文件 libsofile.so 。

第二步:在程序中使用动态库(链接动态库文件)
键入命令:

gcc test.c libsofile.so -o test

在这里插入图片描述
键入命令:./test 运行
在这里插入图片描述

注意:如果出错,可以参照上述 hello 实例中对应地方出现的解决方案。

1.4 练习使用库

此处过程与上述 hello 程序过程类似,不再过多赘述

1.4.1 准备代码

第一步:创建新的目录
分别键入:

mkdir test2
cd test2

在这里插入图片描述
第二步:编写4个 c 语言文件
使用 nano 编辑器,编写四个文件。
在这里插入图片描述

x2x.c

//乘法运算
#include <stdio.h>
void x2x(int x,int y){
	int m = x * y;
	printf("x*y=%d\n",m);
}

x2y.c

//除法运算
#include <stdio.h>
void x2y(int x,int y){
	int n = x / y;
	printf("x/y=%d\n",n);
}

xy.h

#ifndef XY_H
#define XY_H
void x2x(int,int);
void x2y(int,int);
#endif

main.c

#include "xy.h"
int main(){
	x2x(80,20);
	x2y(360,6);
}

第三步:将三个 .c 文件编译成三个 .o 文件。
分别键入:

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

在这里插入图片描述
可见已经有个三个 .o 文件。

1.4.2 生成 .a 静态库文件

第一步:由 .o 文件创建静态库
分别键入:

ar -crv libafile.a x2x.o x2y.o
ls

在这里插入图片描述
可见已有一个 libafile.a 静态库文件。
第二步:在程序中使用静态库
键入:

gcc -o test main.c -L. -lafile

在这里插入图片描述
执行结果:
键入:

./test

在这里插入图片描述

  • 键入命令: ls -lht 或者 ll 可以查看文件夹内的所有文件大小,记下来。
size test

在这里插入图片描述
此时可以看到 test 文件的大小。

1.4.3 生成 .so 动态库文件

第一步:创建动态库文件

  • 删除静态库文件和可执行文件,只保留目标文件
    分别键入:
rm -f libafile.a test
ls

在这里插入图片描述

  • 在系统提示符下键入命令:gcc -shared -fpic -o libsofile.so x2x.o x2y.o (-o不可少),得到动态库文件 libsolife.so。

在这里插入图片描述
可见,生成了动态库文件 libsofile.so 。

第二步:在程序中使用动态库(链接动态库文件)
键入命令:

gcc main.c libsofile.so -o test

在这里插入图片描述
键入命令:./test 运行
在这里插入图片描述

注意:如果出错,可以参照上述 hello 实例中对应地方出现的解决方案。

  • 键入命令:size test可以看到最终的可执行文件大小

在这里插入图片描述
可见文件的大小与之前用静态库链接生成的 test 可执行文件的大小差距不大。

2 总结

根据上述实例及练习,可以了解到我们通常使用的函数库分为静态库与动态库两种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库;动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。当静态库和动态库同时存在的时候,程序会优先使用动态库,而且两者最终的可执行文件的大小差别不大。

3 参考资料

1 、gcc生成静态库.a和动态库.so
2、揭开 gcc 编辑器的面貌

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值