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