【库函数】Linux下动态库.so和静态库.a的生成和使用

简介: 【库函数】Linux下动态库.so和静态库.a的生成和使用

1c80104738644a03afd6533ed0994e30.gif

🌞1. Linux下静态库和动态库的基本概念

库(Library)是一组预先编写好的程序代码,它们被打包在一起以供其他程序使用,从而避免了重复编写相同的代码。库可以分为静态库和动态库两种类型:

静态库

  • 作用:在程序编译的时候,将库编译进可执行程序中, 运行的时候不需要外部函数库
  • 目录:默认库目录 /lib 或 /usr/lib 或 /usr/local/lib
  • 后缀:libxxx.a
  • 命名规范:静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称

动态库

  • 作用:在程序运行的时候,将库加载到程序中,运行的时候需要外部函数库
  • 目录:默认的动态库搜索路径/lib;/usr/lib
  • 后缀:libxxx.so
  • 命名规范:动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号

使用库的主要目的是:

  1. 提高代码的重用性和可维护性
  2. 减少开发人员的工作量
  3. 并使程序更加模块化和易于扩展

常见的库包括:

  1. 标准库(如C标准库和C++标准库)
  2. 第三方库(如图形界面库、数据库访问库、网络通信库等)
  3. 自定义的库(根据项目需求编写的特定功能的库)

对.h头文件的理解    传送门:【头文件】对.h文件的理解-CSDN博客


🌞2. 动态库

🌊2.1 动态库如何生成

下面通过一个小栗子介绍如何生成一个动态库。

  1. 一个头文件:  so_test.h
  2. 头文件接口实现的三个c文件:so_test_a.c  so_test_b.c  so_test_c.c
  3. 我们将这几个文件编译成一个动态库:libtest.so

🌍2.1.1 文件详情

我在路径/root/host/my_program/asoc/include下创建四个文件

一个头文件:

vi so_test.h
#ifndef SO_TEST_H
#define SO_TEST_H
 
int addTwoiNum(int a, int b);
int subTwoiNum(int a, int b);
int mulTwoiNum(int a, int b);
 
#endif

三个.c文件:

vi so_test_a.c
#include "so_test.h"
#include <stdio.h>
 
int addTwoiNum(int a, int b) {
    return a + b;
}
vi  so_test_b.c
#include "so_test.h"
#include <stdio.h>
 
int subTwoiNum(int a, int b) {
    return a - b;
}
vi so_test_c.c
#include "so_test.h"
#include <stdio.h>
 
int mulTwoiNum(int a, int b) {
    return a * b;
}

🌍2.1.2 编译生成动态库

给文件附上权限:

chmod 777 so_test_a.c so_test_b.c so_test_c.c so_test.h

接下来,我们将编译这些文件成一个动态库。

在Linux系统中可以使用gcc来完成这个任务。

gcc -c -Wall -Werror -fpic so_test_a.c  so_test_b.c  so_test_c.c
gcc -shared -o libtest.so so_test_a.o so_test_b.o so_test_c.o

第一行命令

  • -c 选项告诉编译器只编译源文件,而不进行链接。
  • -fpic 选项用于生成与位置无关的代码,这是动态链接库所必需的。

第二行命令:

  • 使用 -shared 选项将目标文件链接成一个共享对象(动态库) libtest.so

现在,会得到一个名为 libtest.so 的动态库文件。


🌊2.2 动态库如何使用

前面已经成功生成了一个动态链接库libtest.so,下面通过一个程序来调用这个库里的函数。

比如程序的源文件为:main.c【我创建的目录是/root/host/my_program/asoc/my_program】

#include <stdio.h>
#include "so_test.h"
 
int main() {
    int result_a, result_b, result_c;
    int x = 10, y = 5;
 
    // 调用动态库中的函数
    result_a = addTwoiNum(x, y);
    result_b = subTwoiNum(x, y);
    result_c = mulTwoiNum(x, y);
 
    // 打印结果
    printf("Result of add: %d\n", result_a);
    printf("Result of sub: %d\n", result_b);
    printf("Result of mul: %d\n", result_c);
 
    return 0;
}

现在需要链接 libtest.so 到源文件。

下面是编译模板:

gcc -o main main.c -I/path/to/include -L/path/to/lib -ltest

模板参数说明:

  • -o main:指定输出文件的名称为 main
  • main.c:您的源文件。
  • -I/path/to/include:指定要搜索头文件的路径。
  • -L/path/to/lib:指定要搜索库文件的路径。
  • -ltest:指定要链接的库文件名称。这里假设动态库文件名为 libtest.so

请将 /path/to/include/path/to/lib 替换为实际的路径。


🌍2.2.1 案例

【案例】如果头文件路径是 /root/host/my_program/asoc/include/so_test.h,动态库文件路径是 /root/host/my_program/asoc/include/libtest.so,可以这样编译 main.c 文件:

gcc -o main main.c -I/root/host/my_program/asoc/include -L/root/host/my_program/asoc/include -ltest

在这个命令中:

  • -o main:指定输出文件的名称为 main
  • main.c:源文件。
  • -I/root/host/my_program/asoc/include:指定要搜索头文件的路径。
  • -L/root/host/my_program/asoc/include:指定要搜索库文件的路径。
  • -ltest:指定要链接的库文件名称。

链接完成会生成一个 main 的可执行文件,这个可执行文件到底有没有成功链接到动态链接库呢?

可以使用下面的命令来查看:

ldd main

这里说明虽然我们已经使用 -L 选项指定了库文件的搜索路径,但是系统加载器在搜索动态库时还是会按照默认的路径 /lib  或者 /usr/lib 的路径进行搜索,因此即使编译成功,但运行时仍找不到动态库。

要解决这个问题,可以尝试设置 LD_LIBRARY_PATH 环境变量来指定动态库的搜索路径。例如我的动态库.so是在路径/root/host/my_program/asoc/include下,则使用命令:

LD_LIBRARY_PATH=/root/host/my_program/asoc/include ./main

这样运行时就能够找到动态库 libtest.so+运行成功!


🌍2.2.2 动态库错误记录

这个错误是在动态库执行的时候经常会遇到,说找不到这个.so文件,如果放在/lib或者/usr/lib下,那么默认就能找到。如果放在其他目录下,有 3 种解决方案:

  1. 将.so 文件拷贝到 /usr/lib/文件夹下面
  2. 添加PATH环境变量【前面的案例就是使用这个解决】
    export LD_LIBRARY_PATH=<动态库所在的绝对路径>
  3. 修改配置脚本
    将动态库所在的路径加到  /etc/ld.so.conf 文件里
vim /etc/ld.so.conf
  1. 添加后刷新
/sbin/ldconfig

🌞3. 静态库

🌊3.1 静态库如何生成

下面通过一个小栗子介绍如何生成一个静态库。

  1. 一个头文件:  vi staticlib.h
  2. 头文件接口实现的三个c文件:staticlib.c
  3. 我们将这几个文件编译成一个静态库:libstatic.a

🌍3.1.1 文件详情

我在路径/root/host/my_program/asoc/include下创建下面的文件

vi staticlib.h
#ifndef __STATICLIB_H
#define __STATICLIB_H
 
int hello();
 
#endif
vi staticlib.c
#include "staticlib.h"
#include <stdio.h>
 
int hello(){
    printf("hello,this is static lib\n");  
    return 0;
}

🌍3.1.2 编译生成动态库

给文件附上权限:

chmod 777 staticlib.h staticlib.c

使用编译器将 staticlib.c 编译成目标文件(.o 文件):

gcc -c staticlib.c -o staticlib.o

使用 ar 命令将目标文件打包成静态库文件 libstatic.a

ar rcs libstatic.a staticlib.o

这样就生成了名为 libstatic.a 的静态库文件,其中包含了 staticlib.o 的内容。


🌊3.2 静态库如何使用

前面已经成功生成了一个动态链接库libtest.so,下面通过一个程序来调用这个库里的函数。

比如程序的源文件为:test.c【我创建的目录是/root/host/my_program/asoc/my_program】

内容如下:

#include <stdio.h>
#include "staticlib.h"
 
int main() {
    printf("Calling hello() function...\n");
    hello();
    return 0;
}

接下来,需要编译 main.c 并链接静态库 libstatic.a

gcc test.c -o test -I/root/host/my_program/asoc/include/ -L/root/host/my_program/asoc/include/ -lstatic

参数说明:

  • -L 参数指定了编译器搜索库文件的路径
  • -lstatic 指定了要链接的静态库名字(注意,lib 前缀和 .a 扩展名都不需要在此处指定)

然后运行可执行文件 test

./test

说明静态库链接成功!


目录
相关文章
|
3月前
|
安全 Linux vr&ar
Linux的动态库和静态库
Linux的动态库和静态库
|
1月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
85 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
3月前
|
Linux API
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
|
4月前
|
Oracle 关系型数据库 Linux
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
通过这一连串的步骤,可以专业且有效地在Linux下为Qt编译Oracle驱动库 `libqsqloci.so`,使得Qt应用能够通过OCI与Oracle数据库进行交互。这些步骤适用于具备一定Linux和Qt经验的开发者,并且能够为需要使用Qt开发数据库应用的专业人士提供指导。
150 1
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
|
3月前
|
Linux 网络安全 API
【Azure 应用服务】App Service For Linux 环境中,如何从App Service中获取GitHub私有库(Private Repos)的Deploy Key(RSA key)呢?
【Azure 应用服务】App Service For Linux 环境中,如何从App Service中获取GitHub私有库(Private Repos)的Deploy Key(RSA key)呢?
|
3月前
|
小程序 Linux 开发者
Linux之缓冲区与C库IO函数简单模拟
通过上述编程实例,可以对Linux系统中缓冲区和C库IO函数如何提高文件读写效率有了一个基本的了解。开发者需要根据应用程序的具体需求来选择合适的IO策略。
32 0
|
5月前
|
存储 Linux C语言
Linux|如何安装和运行多个 glibc 库
Linux|如何安装和运行多个 glibc 库
1098 5
|
5月前
|
Linux 编译器 C语言
Linux中的pkg-config:简化库依赖管理的利器
**pkg-config**是Linux下管理库依赖的工具,它通过读取库的`.pc`文件提供编译和链接参数。使用`pkg-config --cflags --libs &lt;library&gt;`获取编译和链接选项,例如`gcc -o test test.c $(pkg-config --cflags --libs glib-2.0)`。能进行版本检查、参数提取、依赖管理和路径搜索。列出所有包用`pkg-config --list-all`。最佳实践包括确保库正确安装、检查版本、配置`PKG_CONFIG_PATH`及使用构建工具。
|
5月前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
43 1
|
4月前
|
Linux 编译器 vr&ar
【Linux】静态库和动态库
本文详细介绍了Linux系统中静态库和动态库的概念、区别、制作与使用方法,包括它们在链接时的区别、加载机制以及优缺点。
56 0