【嵌入式知识02】Linux下用GCC生成静态库和动态库过程

 本文主要介绍什么是静态库与动态库以及他们的区别,在Linux中如何通过gcc创建与使用静态库、动态库。

目录

一、什么是静态库和动态库

静态库

动态库

二、用gcc生成静态库和动态库

步骤1:编辑生成例子程序

步骤2:将hello.c编译成.o文件

步骤3:由.o文件创建静态库

步骤4:在程序中使用静态库

步骤5:由.o文件创建动态库文件

步骤6:在程序中使用动态库

知识点

三、实例

1、题目要求

2、步骤

2.1编辑程序

2.2 将.c文件编译成.o文件

2.3 静态库生成及使用

2.4 动态库的生成及使用

四、总结

参考资料


一、什么是静态库和动态库

        我们通常将一些公用函数制作成函数库,供其它程序使用。这类已经写好的,可以复用的代码便是库。其本质上来说是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库分为两种:静态库(.a、.lib)和动态库(.so、.dll)。

  • 静态库

        静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

  • 动态库

        动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

        两者区别:前者是编译连接的,后者是程序运行载入的。

二、用gcc生成静态库和动态库

      我们通过下面的举例说明在Linux中如何创建静态库和动态库,以及使用他们。  在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。

步骤1:编辑生成例子程序

先创建一个作业目录,保存练习的文件。

mkdir test1
cd test1

再用vim文本编辑器生成所需要的三个文件:hello.hhello.cmain.c

hello.h

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

hello.c

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

main.c

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

步骤2:将hello.c编译成.o文件

无论静态库还是动态库,都是由.o文件创建的。因此,必须将源程序hello.c通过gcc先编译成.o文件,在系统提示符下键入以下命令得到hello.o文件。

输入指令:gcc -c hello.c

运行 ls 命令查看是否生成了 hello.o 文件: 

实际所得结果如下:

步骤3:由.o文件创建静态库

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

例如:我们将创建的静态库名为 myhello,则静态库文件名就是 libmyhello.a 。在创建和使用静态库时,需要注意这点:

创建静态库用  ar  命令。在系统提示符下键入以下命令将创建静态库文件  libmyhello.a 

输入指令:ar -crv libmyhello.a hello.o ,再运行指令  ls  查看结果:

实际运行结果如下所示:

 ls 命令结果中有  libmyhello.a 

步骤4:在程序中使用静态库

问:静态库制作完成后,如何使用其内部的函数呢?

答:只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用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

动态库连接时也可以这样做。

步骤5:由.o文件创建动态库文件

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

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

gcc -shared -fPIC -o libmyhello.so hello.o
shared:表示指定生成动态链接库,不可省略
-fPIC:表示编译为位置独立的代码,不可省略

使用 ls 命令查看动态库文件是否生成,实际运行结果如下所示:

 得到了动态库文件  libmyhello.so

步骤6:在程序中使用动态库

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

我们运行 gcc 命令生成目标文件,再运行它观察结果。

# gcc -o hello main.c -L.-Imyhello

但是之后./hello 会报错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到/usr/lib 中找库文件的,将文件 libmyhello.so 复制到目录 /usr/lib  中就可以了。

mv libmyhello.so /usr/lib
./hello

得到结果:Hello everyone!

知识点

静态库与动态库比较

gcc编译得到.o文件 gcc -c hello.c
创建静态库 ar -crv libmyhello.a hello.o
创建动态库 gcc -shared -fPIC -o libmyhello.so hello.o
使用库生成可执行文件 gcc -o hello main.c -L. -lmyhello
执行可执行文件 ./hello

生成动态库的三种方式

  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就正确了。
 

三、实例

1、题目要求

1)编写一个主程序文件main.c 和两个子程序文件 sub1.c,sub2.c,
要求:子程序sub1.c 包含一个算术运算函数 float x2x(int a,int b),此函数功能为对两个输入整型参数做某个运算,将结果做浮点数返回;再扩展写一个x2y函数(功能自定);
main函数代码将调用x2x和x2y ;返回结果printf出来。
2)将这3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;
将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小。
3)将x2x、x2y目标文件用 ar工具生成1个 .so 动态库文件, 然后用 gcc将 main函数的目标文件与此动态库文件进行链接,生成最终的可执行程序,记录文件的大小,并与之前做对比。
 

2、步骤

2.1编辑程序

创建一个目录,用来保存此次练习的文件:

mkdir test3
cd test3

利用vim文本编辑器编辑需要的文件sub1.csub2.csub.hmain.c

sub1.c

/*sub1.c*/
float x2x(int x,int y)
{
	float r;
	r=x+y;
	return r;
}

sub2.c

/*sub2.c*/
float x2y(int x,int y)
{
	float r;
	r=x*y;
	return r;
}

sub.h

/*sub.h*/
#ifndef SUB_H
#define SUB_H
float x2x(int x,int y);
float x2y(int x,int y);
#endif

main.c

/*main.c*/
#include<stdio.h>
#include"sub.h"
int main()
{
    int x,y;
    x=2;
    y=3;
    printf("x+y=%f\n",x2x(x,y));
    printf("x*y=%f\n",x2y(x,y));
    return 0;
}

2.2 将.c文件编译成.o文件

键入以下命令将三个.c文件编译成.o文件

gcc -c sub1.c
gcc -c sub2.c
gcc -c main.c

使用 ls 命令可查看结果

生成了sub1.o,sub2.o,main.o文件

2.3 静态库生成及使用

将两个目标文件用 ar 工具生成 .a 静态库        

ar -crv libsub.a sub1.o sub2.o

生成了 libsub.a 

 程序中使用静态库:

gcc -o sub main.c -L. -lsub
./sub

运行之后即可得到结果

2.4 动态库的生成及使用

创建动态库文件libsub.so,并使用该动态库

输入以下指令:

gcc -shared -fPIC -o libsub.so sub1.o sub2.o
gcc -o sub main.c -L. -lmyhello
./sub

至此,main函数的目标文件与动态库的链接,以及最终可执行程序生成完毕。

四、总结

        本次主要学习了使用gcc创建与使用静态库和动态库,整个过程我对静态库与动态库的生成更加熟悉了,也能熟练地使用相关基础操作。通过静态库与动态库的比较,两者的差异能明显辨别出来。整个作业完成过程中,遇到了很多困难,通过查询资料,解决了困难,可谓受益匪浅。

参考资料

https://blog.csdn.net/qq_43279579/article/details/109026927

https://blog.csdn.net/qq_46467126/article/details/120619492?spm=1001.2014.3001.5502

https://blog.csdn.net/qq_47281915/article/details/120615756?spm=1001.2014.3001.5502

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小梅同学charles

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值