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

一、静态库和动态库

1.库的含义

  • 库就是已经写好的,成熟的,可以直接使用的代码,通常情况下,将已经写好的一些公用函数制作成函数库,提供给使用者和其他程序反复使用。
  • 从本质上来说,库是一种可执行代码的二进制形式,可被操作系统载入内存执行。
  • 库分为静态库和动态库两种。

2.静态库(.a)

  • 静态库:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库。
  • 静态库的特点是可执行文件中包含了库代码的一份完整拷贝, 使得程序在运行时与函数库再无联系,移植方便。
  • 静态库的缺点是被多次使用就会有多份冗余拷贝,使得空间和资源被浪费。并且,即使仅当静态库的某一小部分获得了更新,那么所有的程序都会被重新下载。

3.动态库(.so)

  • 动态库:在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。
  • 动态库的优点是解决了静态库对空间和资源造成的浪费,也使得当库更新时,用户仅需更新改动的部分。

4.静态库和动态库的区别

  • 静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系。
  • 动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。

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

1.准备工作

(1)创建目录

  • 打开Document下的terminal(终端)
    在这里插入图片描述
  • terminal中输入以下指令,创建一个名为test1的目录并将此目录切换为目标目录
mkdir test1  /*创建名为test1的目录*/
cd test1    /*切换工作目录为test1*/
  • 如图,在Document下出现了名为test1的新目录
    在这里插入图片描述

(2)创建文件

  • 创建文件,以用于代码的存放,创建文件的详细操作请参考博客

如何安装ubuntu系统下,并在ubuntu系统下使用gcc和Makefile编程

  • 通过终端指令创建好三个用于存放代码的文件
    在这里插入图片描述

(3)编写代码

  • 在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;
}

输入代码保存完毕后,文件如图
在这里插入图片描述

(4)gcc编译得到.o文件

  • 在终端输入指令gcc 文件名 -o 文件名或者gcc -c 文件名,可得到.o文件,详细的操作请参考博客

如何安装ubuntu系统下,并在ubuntu系统下使用gcc和Makefile编程

  • 如图,成功编译得到.o文件
    在这里插入图片描述

2.静态库(.a)的生成和使用

(1)由.o文件创建静态库文件

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

  • 在终端输入指令ar -crv lib静态库名.a 文件名.o,可由.o文件创建一个静态库文件,前缀是lib
  • 如图,输入指令ar -crv libmyhello.a hello.o,可得到libmyhello.a静态库文件
    在这里插入图片描述

(2)在程序中使用静态库

只需在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明静态库名,gcc 将会从静态库中将公用函数连接到目标文件中。

  • 有三种方法可以生成目标文件,使得静态库可以在程序中使用
gcc -o hello main.c -L. –lmyhello
gcc main.c libmyhello.a -o hello
gcc -c main.c
gcc -o hello main.o libmyhello.a
  • 如图,采用第一种方法生成目标文件hello
    在这里插入图片描述

  • 在终端中输入指令./hello,执行hello文件,验证其是否可以正常运行
    在这里插入图片描述
    显示Hello everyone!,程序可以正常运行

  • 在终端中输入指令rm libmyhello.a,移除静态库后,再次运行hello,验证静态库中的公用函数是否已经全部连接到目标文件中。
    在这里插入图片描述
    移除静态库后,目标文件仍然能够正常运行,表明静态库中的公用函数已经连接到目标文件中。

3.动态库(.so)的生成和使用

(1)动态库的生成

动态库文件名命名规范和静态库文件名命名规范类似,只是文件拓展名改为.so

  • 在终端中输入指令gcc -shared -fPIC -o libmyhello.so hello.o,即可生成动态库文件libmyhello.so
    在这里插入图片描述

(2)在程序中使用动态库

  • 通过gcc指令生成目标文件,在终端输入指令gcc main.c libmyhello.so -o hello,生成连接了动态库的名为hello的目标文件
    在这里插入图片描述
  • 通过在终端输入指令./hello来运行hello文件,验证连接是否成功
    在这里插入图片描述
  • 如上图,出现了error(错误),其原因是No such file or directory,即没有找到动态库。
  • 具体解决方法是先将文件 libmyhello.so复制到目录/usr/lib中,即在终端中输入指令mv libmyhello.so /usr/lib后,输入./hello执行hello文件
    在这里插入图片描述
  • 如上图,出现error(错误):Permission denied(权限谨慎使用)
  • 解决办法:使用root权限,详细参考博客:Linux下出现permission denied的解决办法
    首先输入指令su root,然后输入密码,若发现首部变为root,尾部的$ 变为了#,则说明已经成功
    在这里插入图片描述
  • 现在再将libmyhello.so移动到/usr/lib/目录中,并执行hello文件,在终端中输入指令mv libmyhello.so /usr/lib,然后输入指令./hello,执行hello文件
    在这里插入图片描述
  • 如上图,此时文件夹中已经没有libmyhello.so文件,表明该文件已经转移成功,执行hello文件后,显示Hello everyone!表明函数连接成功

4.分析静态库和动态库

思考:当静态库和动态库同名时,gcc 命令会使用哪个库文件呢?

  • 首先先将除了.h和.c以外的文件删除,只保留.h和.c文件,如图所示
    在这里插入图片描述

  • 创建静态库文件libhello.a和动态库文件libhello.so
    在这里插入图片描述

  • 生成目标文件hello
    在这里插入图片描述

  • 现在运行hello目标文件,验证其优先使用哪个库
    在这里插入图片描述

  • 发现出现找不到库的错误,这表明在静态库和动态库同名同时存在的情况下,会优先使用动态库

三、实例

1.实例1

具体的过程参考上述hello的建立过程

(1)代码部分

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);
}
  • 文件创建如图
    在这里插入图片描述

(2)生成.o文件

指令:gcc -c A1.c A2.c
在这里插入图片描述

(3)静态库的构建和使用

指令ar -crv libfile.a A1.o A2.ogcc -o test test.c libfile.a
在这里插入图片描述

(4)动态库的构建和使用

指令:gcc -shared -fPIC -o libfile.so A1.o A2.ogcc -o test test.c libfile.so
在这里插入图片描述

2.实例2

具体的过程参考上述hello的建立过程

(1)代码部分

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)生成.o文件

指令:gcc -c sub1.c sub2.c
在这里插入图片描述

(3)静态库的构建和使用

指令ar -crv libsub.a sub1.o sub2.ogcc -o main main.c libsub.a
在这里插入图片描述

(4)动态库的构建和使用

指令:gcc -shared -fPIC -o libsub.so sub1.o sub2.ogcc -o main main.c libsub.so
在这里插入图片描述

四、总结

总的来说,静态库和动态库的操作还是比较简单的,不过还是需要大家亲自操作,将理论在实践中验证。本篇博客仅供大家参考,若博客中存在纰漏,希望大家斧正。

五、参考文献

gcc生成静态库.a和动态库.so
Linux下出现permission denied的解决办法
静态库 - 百度百科

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值