静态库、动态库的生成与使用

本文详细介绍了如何在Linux环境下使用gcc生成静态库.a和动态库.so,包括从创建源文件到编译、链接的完整步骤。通过实例展示了静态库和动态库的使用,并解释了在动态库和静态库同名时,gcc编译器的选择优先级。此外,还补充了关于编译参数、动态库查找路径及解决找不到动态库问题的方法。
摘要由CSDN通过智能技术生成

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

函数库分为静态库和动态库两种。 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程 序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

1、编辑生成例子程序 hello.h、hello.c 和 main.c

打开Linux终端,先创建一个作业目录,保存本次练习的文件。
在这里插入图片描述
然后用 vim、nano 或 gedit 等文本编辑器编辑生成所需要的 3 个文件。
hello.h:
在这里插入图片描述
hello.c:
在这里插入图片描述
main.c:
在这里插入图片描述

2、将 hello.c 编译成.o 文件

在这里插入图片描述
我们运行 ls 命令看看是否生存了 hello.o 文件:
在这里插入图片描述
在 ls 命令结果中,我们看到了 hello.o 文件,本步操作完成。

3、由.o 文件创建静态库

静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为 myhello,则静态库文件名就是 libmyhello.a。在创建和使用静态库时, 需要注意这点。创建静态库用 ar 命令。

在系统提示符下键入以下命令将创建静态库文件 libmyhello.a:
在这里插入图片描述
我们同样运行 ls 命令查看结果:
在这里插入图片描述
ls 命令结果中有 libmyhello.a

4、在程序中使用静态库

使用静态库内部的函数:只需要在使用到这些公用函数的源程序中包 含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明静态库名,gcc 将会从 静态库中将公用函数连接到目标文件中。注意,gcc 会在静态库名前加上前缀 lib,然后追 加扩展名.a 得到的静态库文件名来查找静态库文件。

在程序 3:main.c 中,我们包含了静态库的头文件 hello.h,然后在主程序 main 中直接调用 公用函数 hello。下面先生成目标程序 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 中了。
在这里插入图片描述
程序照常运行,静态库中的公用函数已经连接到目标文件中了。
我们继续看看如何在 Linux 中创建动态库。

5、由.o 文件创建动态库文件

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

用 gcc 来创建动态库。 在系统提示符下键入以下命令得到动态库文件 libmyhello.so。

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

(-o 不可少)
我们照样使用 ls 命令看看动态库文件是否生成:
在这里插入图片描述

6、在程序中使用动态库

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明动态库名进行编译。

我们先运行 gcc 命令生成目标文件,再运行它看看结果:
在这里插入图片描述
(或 gcc main.c libmyhello.so -o hello不会出错(没有 libmyhello.so 的话,会出错),但是接下来./hello 会提示出错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到 /usr/lib 中找库文件的,将文件 libmyhello.so 复制到目录/usr/lib 中就 OK 了)
在这里插入图片描述出错了。看错误提示,原来是找不到动态库文件 libmyhello.so。程序在运行时, 会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提 示类似上述错误而终止程序运行。我们将文件 libmyhello.so 复制到目录/usr/lib 中,再试试:
在这里插入图片描述成功了。这也进一步说明了动态库在程序运行时是需要的。 我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的 gcc 命令完全一样, 那当静态库和动态库同名时,gcc 命令会使用哪个库文件呢?抱着对问题必究到底的心情, 来试试看。 先删除除.c 和.h 外的所有文件,恢复成我们刚刚编辑完举例程序状态。
在这里插入图片描述
再来创建静态库文件 libmyhello.a 和动态库文件 libmyhello.so:

gcc -c hello.c # ar -cr libmyhello.a hello.o (或-cvr )
gcc -shared -fPIC -o libmyhello.so hello.o 

在这里插入图片描述
通过上述最后一条 ls 命令,可以发现静态库文件 libmyhello.a 和动态库文件 libmyhello.s o 都已经生成,并都在当前目录中。然后,我们运行 gcc 命令来使用函数库 myhello 生成目 标文件 hello,并运行程序 hello。

gcc -o hello main.c -L. –lmyhello

(动态库和静态库同时存在时,优先使用动态库,当然,如果直接 #gcc main.c libmyhello.a -o hello 的话,就是指定为静态库了)
在这里插入图片描述
从程序 hello 运行的结果中很容易知道,当静态库和动态库同名时,gcc 命令将优先使用动 态库,默认去连/usr/lib 和/lib 等目录中的动态库,将文件 libmyhello.so 复制到目录/usr/lib 中即可。
在这里插入图片描述

补充

1:编译参数解析

最主要的是 GCC 命令行的一个选项:
-shared该选项指定生成动态连接库(让连接器生成 T 类型的导出符号表,有时候也生成弱连接 W 类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。
-fPIC 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-L. 表示要连接的库在当前目录中;(多个库:在编译命令行中,将使用的静态库文件放在源文件后面就可以了。比如:gcc -L/usr/lib myprop.c libtest.a libX11.a libpthread.a -o myprop 其中-L/usr/lib 指定库文件的查找路径。编译器默认在当前目录下先查找指定的库文件,如前面的“法二 #gcc main.c libmyhello.a -o hello”)
-lmyhello 编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上 lib,后面 加上.so 或.a 来确定库的名称 libmyhello.so 或 libmyhello.a。
LD_LIBRARY_PATH 这个环境变量指示动态连接器可以装载动态库的路径。 当然如果有 root 权限的话,可以修改/etc/ld.so.conf 文件,然后调用 /sbin/ldconfig 来达到 同样的目的,不过如果没有 root 权限,那么只能采用输出 LD_LIBRARY_PATH 的方法了。
调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include 进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过 ldd 命令察看 时,就是死活找不到你指定链接的 so 文件,这时你要作的就是通过修改 LD_LIBRARY_PATH 或者/etc/ld.so.conf 文件来指定动态库的目录。通常这样做就可以解决 库无法链接的问题了。

2:找到生成的动态库的 3 种方式:

(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 刷新。 这样, 加入的目录下的所有库文件都可见。
附:像下面这样指定路径去连接系统的静态库,会报错说要连接的库找不到:
g++ -o main main.cpp -L/usr/lib libpthread.a
必须这样:
g++ -o main main.cpp -L/usr/lib -lpthread 才正确 。
自定义的库考到/usr/lib 下时, g++ -o main main.cpp -L/usr/lib libpthread.a libthread.a libclass.a 会出错,但是 g++ -o main main.cpp -L/usr/lib -lpthread -lthread -lclass 就正确了。

二、静态库.a与.so库文件的生成与使用

1、编辑四个文件:A1.c A2.c A.h test.c

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文件的生成与使用

生成目标文件(xxx.o):

gcc -c A1.c A2.c

在这里插入图片描述
生成静态库.a文件:

ar crv libafile.a A1.o A2.o

在这里插入图片描述
使用.a库文件,创建可执行程序(若采用此种方式,需保证生成的.a文件与.c文件保存在同一目录下,即都在当前目录下):

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

发现出现错误:
在这里插入图片描述
运行ldd test,查看链接情况:
在这里插入图片描述
发现确实是找不到对应的.so文件。

这是由于linux自身系统设定的相应的设置的原因,即其只在/lib and /usr/lib下搜索对应的.so文件,故需将对应so文件拷贝到对应路径。

sudo cp libsofile.so /usr/lib

再次执行./test,即可成功运行。
在这里插入图片描述
同时可直接使用gcc -o test test.c -L. -lname,来使用相应库文件

其中,

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

三、实例使用静动态库

1、程序代码

第一次作业的程序代码基础上进行改编:
sub1.c:

#include "sub1.h"
float x2x(int a,int b)
{
    float x=(float)a;
    float y=(float)b;
    return x+y;
}

sub2.c:

#include "sub1.h"
float x2y(int a,int b)
{
        float x=(float)a;
        float y=(float)b;
        return x/y;
}

sub1.h:

#include <stdio.h>
float x2x(int a,int b);
float x2y(int a,int b);

main1.c:

#include <stdio.h>
#include "sub1.h"
int main()
{
int a,b;
a=7;
b=10;
printf("a+b=%f",x2x(a,b));
printf("\n");
printf("a/b=%f",x2y(a,b));
printf("\n");
return 0;
}

2、静态库的使用

在这里插入图片描述
静态库大小:2.7KB
在这里插入图片描述

3、动态库的使用

创建动态库:
在这里插入图片描述
将动态库与目标文件链接:在这里插入图片描述
将对应so文件拷贝到对应路径,运行可执行文件:
在这里插入图片描述
动态库大小:8.1KB
在这里插入图片描述
可以看出:静态库比动态库小得多。

参考文献

Linux下静态库.a与.so库文件的生成与使用——by涛S依J

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值