《C语言杂记》静态库和动态库(Linux版)

2024-08-30 12:32

本文主要是介绍《C语言杂记》静态库和动态库(Linux版),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1静态库和动态库概述

库是一种软件组件技术,库里面封装了数据和函数。库的使用可以使程序模块化。库有两种:静态库和动态库Windows系统包括静态链接库(.lib文件)和动态链接库(.dll文件)。Linux通常把库文件存放在/usr/lib或/lib目录下。Linux库文件名由:前缀lib、库名和后缀3部分组成,其中动态链接库以.so作为后缀,静态链接库通常以.a作为后缀

何为静态库和动态库?

静态库(Static library, Statically-linked library, LIB)或称静态链接库,是一个外部函数与变量的集合体。静态库的文件内容,通常包含一堆程序员自定的变量与函数,在编译期间由编译器与连接器将它集成至应用程序内,并制作成目标文件以及可以独立运作的可执行文件。而这个可执行文件与编译可执行文件的程序,都是一种程序的静态创建(static build)。其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。即静态库中的指令全部被直接包含在最终生成的可执行文件中。

动态库(Dynamic library, Dynamic-link library, DLL)或称动态链接库,是微软公司在微软视窗操作系统中实现共享函数库概念的一种实现方式。动态链接库可被多个程序同时使用。所谓动态链接,就是把一些经常会共用的代码(静态链接的OBJ程序库)制作成DLL档,当程序有需求时函数才进行链接。透过动态链接方式,存储器浪费的情形将可大幅降低。静态链接库则是直接链接到可执行文件。

一个程序编译成可执行的步骤:

在这里插入图片描述

静态库和动态库的区别在链接阶段如何处理库,如果将库链接到目标代码中则是静态库,而将库链接载入推迟到程序运行的时期则是动态库,可以实现进程之间的资源共享。




2 Linux创建和使用静态库

前面已经介绍了静态库的概念,下面我们通过一个实例来看静态库的使用。

2.1生成静态库

1)这里准备了两个库的源码st1 、st2用它们来制作库libmytest.a,如下

$ ls -l

在这里插入图片描述

$ cat st1.c

#include <stdio.h>
void print1()
{printf("Hello!I am st1!\n ");
}

$ cat st2.c

#include <stdio.h>
void print2()
{printf("Hello!I am st2!\n");
}

$ cat main.c

#include <stdio.h>
int main(int argc, const char *argv[])
{print1();print2();return 0;
}

2)生成libmytest.a文件

创建静态库用ar命令,它将很多.o转换成.a

$ gcc -c st1.c st2.c
$ ar crs libmytest.a st1.o st2.o
$ ls -l

在这里插入图片描述

$ file libmytest.a

在这里插入图片描述

静态库文件libmytest.a已经生成,用file命令查看其属性,发现它确实是归档压缩文件。用ar -t libmytest.a可以查看一个静态库包含了那些obj文件:

$ ar -t libmytest.a

在这里插入图片描述

2.2使用静态库

1.直接使用

$gcc -o test main.c libmytest.a

2.双L链接法
$gcc -o test main.c -lmytest -L.(库所在目录,.表示当前目录)

3.单L链接法(需要配置环境变量LIBRARY_PATH,把库放在所在目录配置)

$gcc -o test main.c -lmytest

前面我们已经写好了main.c,现在测试一下

$ gcc -o test main.c -L. -lmytest
$ ls -l

在这里插入图片描述

$ ./test

在这里插入图片描述

这里gcc的参数-L是告诉编译器库文件的路径是当前目录,-l是告诉编译器要使用的库的名字叫mytest。


2.3静态库总结

1.在一个头文件中声明静态库所导出的函数。
2.在一个源文件中实现静态库所导出的函数。
3.编译源文件,生成可执行代码。
4.将可执行代码所在的目标文件加入到某个静态库中,并将静态库拷贝到系统默认的存放库文件的目录下。

下面通过一个例子来说明:

源文件:mylib.c

#include <stdio.h>
void welcome(void)
{printf("welcome to libmylib\n");
}

1>编译mylib.c生成目标文件:

$gcc -o mylib.o -c mylib.c

2>将目标文件加入到静态库中:

$ar -rcs libmylib.a mylib.o

【注】库文件名以lib开头,以.a结尾。

3>将静态库copy到Linux的库目录(/usr/lib或者/lib)下:(也可以不拷贝,注意配置环境变量)

$sudo cp libmylib.a /usr/lib/libmylib.a //管理员身份

编写调用库函数的测试程序test.c:

#include <stdio.h>
int main(void)
{printf("create and use library:\n");welcome(); return 0;
}

4>使用静态库编译:

$gcc -o test test.c -lmylib

这里注意,编译时无需带上前缀和后缀。

5>运行可执行程序test:

$./test

在这里插入图片描述

在Linux下,可以使用ar命令来创建和修改静态库。

这些在linux下man ar一下就可以得到参数,这里说明几个常用的
d:从库中删除成员文件。
r:在库中加入成员文件,若存在,则替换。
c:创建一个库。
s:无论ar命令是否修改了库内容,都强制重新生成库符号表。
其他的命令用时再man。

【注】gcc -static 文件.c [-o 文件]//全部使用静态库的方法




3 Linux创建和使用动态库

动态库的基本概念
1.动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。

2.动态链接库的名称有别名(soname), 真名(realname)和链接名(linker name)。别名由一个前缀lib,然后是库的名字,再加上一个后缀“.so”构成(“libxxx.so”)。真名是动态链接库真实名称,一般总是在别名的基础加上一个小版本号,发布版本等构成。除此之外,还有一个链接名,即程序链接时使用的库的名字。

3.在动态链接库安装的时候,总是复制文件到某个目录下,然后用一个软连接生成别名,在库文件进行更新的时候,仅仅更新软链接即可。

下面我们通过一个实例来学习如何生成动态库和使用动态库。

3.1生成动态库

1)当前文件夹下有下面四个文件

$ ls -l

在这里插入图片描述

文件内容分别为:

$ cat mylib.h

#ifndef _MYLIB_H_
#define _MYLIB_H_#include <stdio.h>void print1();
void print2();#endif  

$ cat dy1.c

#include "mylib.h"void print1() 
{printf("My first shared lib!\n");
}

$ cat dy2.c

#include "mylib.h" 
void print2() 
{printf("My second shared lib!\n");
}  

$ cat main.c

#include "mylib.h"  int main(int argc, char *argv[])  
{  print1();  print2();  return 0;  
}  

2)这里我们将dy1.c与dy2.c用来创建动态库

$ gcc -fPIC -Wall -c dy1.c dy2.c
$ gcc -shared -o libtest.so dy1.o dy2.o

这里 -fPIC 创建与地址无关的编译程序,-shared指定生成动态链接库。
我们也可以一步到位

$ gcc -o libtest.so -fPIC -shared dy1.c dy2.c

我们可以看到下面已经生成了一个libtest.so

$ ls -l

在这里插入图片描述

3.2使用动态链接库

在编译程序时,使用动态链接库和静态库是一致的,使用”-l库名”的方式,在生成可执行文件的时候会链接库文件。使用如下命令:

$ gcc -o test main.c -L. -ltest
$ ls -l

在这里插入图片描述

这里 -L 指定动态链接库的路劲,-ldtest链接库函数test 。-ltest是动态库的调用规则。Linux系统下的动态库命名方式是lib*.so,而在链接时表示位-l*,*是自己命名的库名。

我们可以看到这里已经生成了test可执行文件,我们可以执行一下:

$ ./test

在这里插入图片描述

可以发现发生了错误,这是因为程序运行时没有找到动态链接库造成的。程序编译时链接动态库和运行时使用动态链接库的概念是不同的,在运行时,程序链接的动态链接库需要在系统目录下才行。

这就到了动态库的路径问题,有三种方法:

1)把库拷贝到/usr/lib和/lib目录下:

$ sudo cp libtest.so /lib

【注】这里要超级用户权限sudo

我们看一下执行结果:

$ ./test

在这里插入图片描述

这里执行结果正确。

2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径

$ export LD_LIBRARY_PATH=pwd:$LD_LIBRARY_PATH

我们可以看到:libtest.so 的路径已经存在

$ ldd test

在这里插入图片描述

我们可以看一下结果:

$ ./test

在这里插入图片描述

也能得到正确结果。

3)添加/etc/ld.so.conf.d/*.conf文件。把库所在的路径加到文件末尾,并执行ldconfig刷新。

$ cd /etc/ld.so.conf.d/
$ ls

在这里插入图片描述

$ sudo vi my.conf
$ cat my.conf

/home/bruceou/demo/libtest.so

在/etc/ld.so.conf.d/下建立my.conf 里面只有一句/home/bruceou/demo/libtest.so即libtest.so的路径,然后执行ldconfig刷新即可。


3.3动态库总结

1.编译动态库
方法一:
命令:gcc -fPIC -Wall -c < filename>.c
命令:gcc -shared -o lib< name>.so < filename>.o

方法二:
命令:gcc < file1>.c < file2>.c < filen>.c -fPIC -shared -o lib< name>.so

2.安装路径
命令:cp lib< name>.so /usr/lib/lib< name>.so//管理员身份

3.动态库的链接
命令:gcc -o < preject_name> < tag_name>.c -L. -l< name>
或者:命令:gcc < tag_name>.c -L. -l< name> -o < preject_name>

4.运行可执行程序




欢迎访问我的网站

BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书


欢迎订阅我的微信公众号

在这里插入图片描述

这篇关于《C语言杂记》静态库和动态库(Linux版)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120828

相关文章

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

linux安装、更新、卸载anaconda实践

《linux安装、更新、卸载anaconda实践》Anaconda是基于conda的科学计算环境,集成1400+包及依赖,安装需下载脚本、接受协议、设置路径、配置环境变量,更新与卸载通过conda命令... 目录随意找一个目录下载安装脚本检查许可证协议,ENTER就可以安装完毕之后激活anaconda安装更