Linux拓展:链接库

简介: Linux拓展:链接库

一.说明

本篇博客介绍Linux操作系统下的链接库相关知识,由于相关概念已在Windows下链接库一文中介绍,本篇博客直接上操作。

二.静态链接库的创建和使用

1.提前看

这里主要介绍的是C语言的链接库技术,而在Linux下实现C语言程序,需要你的虚拟机的WSL具有GCC编译器,如果你不了解,可以看Linux下实现C语言程序

2.静态链接库的创建

前提:准备好要编译的 .c 库文件和 .h 头文件,具体是是什么,请查看Windows下链接库

基本步骤:

1.执行gcc -c myMath.c -o myMath.o 文件

2.使用ls命令查看上一步是否成功

3.使用ar rcs libmyMath.a myMath.o 将所有目标文件打包为一个静态链接库(这里是以一个为例,命令下面介绍)

4.使用ls命令查看上一步是否成功

没错,就这几步,你就简单的实现 静态链接库的建立了。

3.静态链接库的使用

静态链接库的用法很简单,就是和其它目标文件一起参与链接,最终生成一个可执行文件。

基本步骤:

  • 1.同目录下再创建一个 main.c 文件
  • 2.利用vim编辑器正常编写代码
  • 3.利用gcc编译命令实现编译成.o文件
  • 4.开始链接

第四步的链接命令有两种:

 gcc -static main.o libmyMath.a -o main                       <-- 第 1 种
 gcc main.o -o main -static -lmyMath -L /home/test/myMath     <-- 第 2 种

上面两种如果不行,可以使用:

 gcc -L /usr/lib main.o libmymath.a -o main

注意:里面的文件名和路径都要改成你自己文件名和路径,即不变色部分需要修改。

4.演示

64c9e26105f6e62da92e86d1cda8dc17.jpg

三.动态链接库的创建与使用

1.提前看

Windows 平台上生成动态链接库时,需要用__declspec(dllexport)显式地“告诉”编译器哪些函数和变量能被外界调用,这些函数和变量的信息(名称、存储位置)保存在引入库文件(.lib)中,而它们的定义保存在动态链接库文件(.dll)中。


与前者不同,Linux 平台上不再需要生成引入库文件,原因很简单,默认情况下动态链接库中定义的所有函数和变量都允许被外界调用。或者说,动态链接库中不仅保存了所有函数和变量的定义,还保存了能被外界调用的所有函数和变量的信息,所以不需要生成引入库文件。

2.动态链接库的建立

前提和静态链接库一样,需要一个.h文件和.c文件

基本步骤:

  • 1.执行命令 gcc -shared -fPIC myMath.c -o libmyMath.so
  • 2.使用ls命令查看上一步结果

有libmyMath.so文件即成功建立


3.动态链接库的使用

基本步骤:


1 将 main.c 与 myMath.h 放在同一目录,向 main.c 文件中引入 myMath.h 头文件

2.执行gcc main.c libmymath.so -o main.exe命令

3.使用ls命令查看上一步结果结果

4.补充注意

相比之下,你是不是以为和windows相比,Linux下动态链接库既然比静态链接库如此简单,那么你可以试着运行静态链接库和动态链接库最后的可执行文件,你会发现报错:./main.exe: error while loading shared libraries: libmyMath.so: cannot open shared object file: No such file or directory


这是因为执行main.exe文件时,需要调动所有动态链接库及其存储位置,而其中 libmyMath.so 文件的存储位置系统并不直到,有下面几种解决方式:


将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64);

在终端输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中xxx为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效);

修改~/.bashrc或~/.bash_profile文件,即在文件最后一行添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx(xxx为动态库文件的绝对存储路径)。保存之后,执行source .bashrc指令(此方式仅对当前登陆用户有效)。

接下来你重新运行即可成功。

5.演示

87928fc6e907647551241827dd79a2a8.jpg

四.补充知识点

1.建立动态链接库

使用gcc -shared -fPIC myMath.c -o libmyMath.so命令


gcc 命令中,各个选项的含义是:


-shared:表示生成动态链接库;

-fPIC:也可以写成 -fpic,功能是令 GCC 编译器生成动态链接库时,用相对地址表示库中各个函数和变量的存储位置。这样做的好处是,无论动态链接库被加载到内存的什么位置,都可以被多个程序(进程)同时调用;(无论怎样,你都加上)

-o libmyMath.so:-o 选项用于指定生成文件的名称,此命令最终生成的动态链接库文件的文件名为 libmyMath.so。

Linux 平台上,动态链接库文件的命名格式为 libxxx.so,其中 xxx 部分可以自定义。

2.ar

ar 是一个用于创建静态库的命令行工具。


语法:ar rcs libname.a file1.o file2.o file3.o


其中 libname.a 是要创建的库的名称,.a 表示这是一个静态库文件。


file1.o, file2.o, file3.o 是包含目标代码的文件,你可以指定任意数量的文件来创建库。


r, c, 和 s 选项都是必须的,表示:


r: 将新的目标文件添加到库中或者替换库中已有的同名文件。

c: 如果库不存在则创建它。

s: 在库中为每个成员生成符号表。

需要注意的是,Linux 平台上静态链接库的名称不是随意的,通常遵循 libxxx.a 格式,xxx 部分可以自定义。

五.动态链接库的显示调用

Linux 平台下,动态加载库的装载、使用、卸载等操作需要借助以下 4 个函数来完成,使用它们时需要引入<dlfcn.h>头文件。

1.dlopen():打开库文件

语法:void *dlopen(const char *filename, int flag);


其中,filename 参数是共享库文件的路径名,可以是绝对路径或相对路径;flag 参数是一个标志位,用于指定 dlopen() 的行为,可以是以下值之一:


RTLD_LAZY:表示在 dlopen() 返回句柄后,只有在需要时才解析符号。

RTLD_NOW:表示在 dlopen() 返回句柄前,解析所有符号。

RTLD_GLOBAL:表示将库中的符号添加到全局符号表中,以便其他库可以使用这些符号。

RTLD_LOCAL:表示不将库中的符号添加到全局符号表中,而是将其限制在当前库中。

成功调用 dlopen() 函数将返回一个非空的句柄,失败则返回 NULL。通过句柄可以使用 dlsym() 函数获取共享库中的符号地址,使用 dlclose() 函数关闭句柄并卸载共享库。

2. dlsym():从库文件中找到要调用的资源

语法:void *dlsym(void *handle, const char *symbol);


其中,handle 参数是由 dlopen() 返回的共享库句柄,symbol 参数是要查找的符号名称(字符串类型),可以是函数名、变量名或其他标识符。


如果成功找到该符号,则 dlsym() 将返回该符号的地址(指向函数或变量的指针)。否则,dlsym() 将返回 NULL。

3. dlclose():关闭打开的库文件

语法:int dlclose(void *handle);

其中,handle 参数是由 dlopen() 返回的共享库句柄。成功调用 dlclose() 函数将返回零,表示函数调用成功。失败则返回非零值,表示出现错误。

4.例子

#include <stdio.h>
#include <dlfcn.h>
int main() {
    // 打开共享库
    void *handle = dlopen("libmylib.so", RTLD_NOW);
    if (handle == NULL) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return 1;
    }
    // 查找符号
    int (*my_func)(int) = (int (*)(int))dlsym(handle, "my_func");
    if (my_func == NULL) {
        fprintf(stderr, "Error: %s\n", dlerror());
        dlclose(handle);
        return 1;
    }
    // 调用函数
    int result = my_func(42);
    printf("Result: %d\n", result);
    // 关闭共享库
    int close_result = dlclose(handle);
    if (close_result != 0) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return 1;
    }
    return 0;
}

上面的代码打开名为 libmylib.so 的共享库,查找其中名为 my_func 的函数,并调用该函数,最后关闭共享库。这里假设 libmylib.so 中包含一个名为 my_func 的函数,它接受一个 int 类型的参数并返回一个 int 类型的值。


需要注意的是,上面的代码中使用了 dlerror() 函数来获取错误信息。当 dlopen()、dlsym() 或 dlclose() 发生错误时,可以通过调用 dlerror() 函数来获取具体的错误信息。

六.总结

这就是Linux下链接库的知识了,为后面介绍makefile做基础,可以结合windows下链接库一起观看。

相关文章
|
4月前
|
安全 Linux vr&ar
Linux的动态库和静态库
Linux的动态库和静态库
|
4月前
|
Linux 索引
在Linux中,符号链接与硬链接有何区别?
在Linux中,符号链接与硬链接有何区别?
|
2月前
|
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开发知识可参考相关书籍。
97 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
4月前
|
Linux API
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
|
5月前
|
Oracle 关系型数据库 Linux
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
通过这一连串的步骤,可以专业且有效地在Linux下为Qt编译Oracle驱动库 `libqsqloci.so`,使得Qt应用能够通过OCI与Oracle数据库进行交互。这些步骤适用于具备一定Linux和Qt经验的开发者,并且能够为需要使用Qt开发数据库应用的专业人士提供指导。
159 1
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
|
4月前
|
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)呢?
|
4月前
|
小程序 Linux 开发者
Linux之缓冲区与C库IO函数简单模拟
通过上述编程实例,可以对Linux系统中缓冲区和C库IO函数如何提高文件读写效率有了一个基本的了解。开发者需要根据应用程序的具体需求来选择合适的IO策略。
34 0
|
5月前
|
网络协议 Ubuntu Linux
查询Linux中网络链接的状态:networkctl
【7月更文挑战第18天】
112 0
查询Linux中网络链接的状态:networkctl
|
5月前
|
存储 Linux Windows
【Linux】文件系统软硬链接的那些事儿
本文介绍了Linux文件系统的磁盘结构、逻辑结构以及文件和inode的关系,重点讲解了软链接和硬链接的区别,强调了它们在文件管理中的作用。
69 7
|
5月前
|
Linux 编译器 vr&ar
【Linux】静态库和动态库
本文详细介绍了Linux系统中静态库和动态库的概念、区别、制作与使用方法,包括它们在链接时的区别、加载机制以及优缺点。
60 0