本文目录
一、前言
我们通常把一些公用函数制作成函数库,供其他程序使用,函数库分为静态库和动态库两种。
静态库在程序编译时会连接到目标代码中,程序运行时将不再需要该静态库。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入。
本文主要通过举例来说明在Linux中如何创建静态库和动态库,以及使用它们。
二、用gcc生成静态库和动态库
(一).hello实例
1.准备过程
(1) .创建一个作业目录,保存本次练习的文件
#mkdir test1
#cd test1
(2) .程序代码
hello.h为该函数库的头文件
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name)
#endif //HELLO_H
hello1.c是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出“Hello,XXX!"。
#include <stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n",name);
}
main.c为测试库文件的主程序,在主程序中调用了公用函数hello
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
(3) .将hello.c编译成.o文件
在系统提示符下键入以下命令得到hello.o文件
gcc -c hello.c
运行ls命令看看是否生成了hello.o文件
ls
看到有hello.o文件,说明本部操作完成。
2.静态库的使用
(1) .由.o文件创建静态库
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名.a。
ar -crv libmyhello.a hello.o
运行ls命令看看是否生成了静态库文件文件
ls
看到libmyhello.a文件,说明本部操作完成。
(2) .在程序中使用静态库
静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包 含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明静态库名,gcc 将会从 静态库中将公用函数连接到目标文件中。注意,gcc 会在静态库名前加上前缀 lib,然后追 加扩展名.a 得到的静态库文件名来查找静态库文件。 在程序 main.c 中,我们包含了静态库的头文件 hello.h,然后在主程序 main 中直接调用 公用函数 hello。下面先生成目标程序 hello,然后运行 hello 程序看看结果如何。
方法一:
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 libmyhello.a
动态库连接时也可以这样做。
输入./hello
说明操作成功了。
然后我们删除静态库文件试试公用函数hello是否真的连接到目标文件hello中了
rm libmyhello.a
./hello
可以看到libmyhello.a已经被删除,而程序照常运行,说明静态库中的公用函数已经连接到目标文件中。
3.动态库的使用
(1) .由.o文件创建动态库文件
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib,但其 文件扩展名为.so。例如:我们将创建的动态库名为 myhello,则动态库文件名就是 libmyh ello.so。用 gcc 来创建动态库。
在系统提示符下键入以下命令得到动态库文件 libmyhello.so。
gcc -shared -fPIC -o libmyhello.so hello.o
提示错误
这是因为在创建hello.o文件时没有键入-fPIC使不一致导致的
重新输入
gcc -o -fPIC hello.c
之后再输入
gcc -shared -fPIC -o libmyhello.so hello.o
用ls命令查看,发现动态库已经创建成功
(2) .在程序中使用动态库
在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含 这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明动态库名进行编译。程序在运行时, 会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提 示类似上述错误而终止程序运行。我们将文件 libmyhello.so 复制到目录/usr/lib 中在运行,否则会报错。
gcc -o hello main.c -L. -lmyhello
之后输入./hello看程序是否执行
./hello
果然出现了错误。
解决方法是将文件 libmyhello.so 复制到目录/usr/lib 中在运行
输入mv libmyhello.so
提示权限不够
所以我们需要临时权限提高
输入sudo mv libmyhello.so
就可以解决
之后输入./hello
,程序成功运行,如下图所示
(二).linux下静态库.a和.so库文件的生成和使用实例
1.准备过程
(1) .先创建一个作业目录,保存本次示例文件
mkdir test2
cd test2
(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 <stdlib.h>
#include "A.h"
int main()
{
print1(1);
print2("test");
exit(0);
}
2.静态库.a文件的生成与使用
gcc -c A1.c A2.c
ar crv libafile.a A1.o A2.o
使用.a 库文件,创建可执行程序(若采用此种方式,需保证生成的.a 文件与.c 文件保 存在同一目录下,即都在当前目录下)
如图都在libafile文件夹内
gcc -o test test.c libafile.a
./test
如图所示,说明使用成功
3.动态库.so文件的生成与使用
生成目标文件(xxx.o() 此处生成.o 文件必须添加"-fpic"(小模式,代码少),否则在生成.so 文件时会出错)
gcc -c -fpic A1.c A2.c
生成共享库.so 文件
gcc -shared *.o -o libsofile.so
使用.so 库文件,创建可执行程序
gcc -o test test.c libsofile.so
./test
发现出现错误:
./test: error while loading shared libraries: libsofile.so: cannot open shared object file: No such file or directory
运行 ldd test,查看链接情况
ldd test
linux-vdso.so.1 => (0x00007fff0fd95000)
libsofile.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f937b5de000)
/lib64/ld-linux-x86-64.so.2 (0x0000563f7028c000)
发现确实是找不到对应的.so 文件。 这是由于 linux 自身系统设定的相应的设置的原因,即其只在/lib and /usr/lib 下搜索对应 的.so 文件,故需将对应 so 文件拷贝到对应路径。
sudo cp libsofile.so /usr/lib
再次执行./test,即可成功运行。
全过程如图所示
(三).其他实例
1.准备过程
(1) .创建一个作业目录,保存本次练习的文件
#mkdir example1
#cd example1
(2) .实例代码
sub1.c:
float x2x(int a,int b)
{
float c=0;
c=a+b;
return c;
}
sub2.c:
float x2y(int a,int b)
{
float c=0;
c=a/b;
return c;
}
sub.h:
#ifndef SUB_H
#define SUB_H
float x2x(int a,int b);
float x2y(int a,int b);
#endif
main.c:
#include<stdio.h>
#include"sub.h"
void main()
{
int a,b;
printf("Please input the value of a:");
scanf("%d",&a);
printf("Please input the value of b:");
scanf("%d",&b);
printf("a+b=%.2f\n",x2x(a,b));
printf("a/b=%.2f\n",x2y(a,b));
}
2.静态库使用
gcc -c sub1.c sub2.c
ar crv libsub.a sub1.o sub2.o
gcc -o main main.c libsub.a
可以看到输入./main
,按要求输入a,b,可以看到输出是正确的,说明程序正确执行。
3.动态库的使用
gcc -shared -fPIC -o libsub.so sub1.o sub2.o
gcc -o main main.c libsub.so
sudo mv libsub.so /usr/lib
可以看到输入./main
,按要求输入a,b,可以看到输出是正确的,说明程序正确执行。
4.静态库与动态库的生成文件大小的比较
静态库
动态库
可以看到态库要比动态库要小很多,生成的可执行文件大小也存在较小的差别。