继《Windows下动态链接库的创建和使用》一节后,Linux 平台又是如何创建和使用动态链接库的呢?接下来,我们以 Ubuntu 系统上的 GCC 编译器为例,详细地讲解如何创建一个动态链接库,以及如何将某个动态链接库引入到我们自己的项目中。
Linux 平台上,我们更习惯将动态链接库称为“共享库文件”或者“共享对象文件”,后缀名通常为 .so。
绝大多数 Linux 发行版都默认安装了 GCC 编译器,如果您不确定当前 Linux 发行版是否装有 GCC,打开 Terminal 命令行工具并执行gcc --version指令:
这是笔者在 Ubuntu 系统上的执行结果,当前系统安装了 9.3.0 版本的 GCC 编译器。如果输出信息为:
表明当前系统没有安装 GCC,读者可以阅读《GCC编译器下载和安装教程》一文下载并安装 GCC 编译器。
Windows 平台上生成动态链接库时,需要用__declspec(dllexport)显式地“告诉”编译器哪些函数和变量能被外界调用,这些函数和变量的信息(名称、存储位置)保存在引入库文件(.lib)中,而它们的定义保存在动态链接库文件(.dll)中。
与前者不同,Linux 平台上不再需要生成引入库文件,原因很简单,默认情况下动态链接库中定义的所有函数和变量都允许被外界调用。或者说,动态链接库中不仅保存了所有函数和变量的定义,还保存了能被外界调用的所有函数和变量的信息,所以不需要生成引入库文件。
接下来,我们以 mymath.c 为例演示创建动态链接库的整个过程,如下为 myMath.h 和 myMath.c 文件中的内容:
//myMath.h
//实现两个整数相加,返回它们的和
int add(int a, int b);
//实现两个整数相减,返回它们的差
int sub(int a, int b);
//实现两个整数相乘,返回它们的乘积
int mul(int a, int b);
//实现两个整数相除,返回它们的商
int div(int a, int b);
//myMath.c
#include "myMath.h"
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
int mul(int a, int b) {
return a * b;
}
int div(int a, int b) {
if (b != 0) {
return a / b;
}
return -1;
}
Linux 平台上,用 GCC 编译器将 myMath.c 转换成动态链接库文件,只需要执行如下指令:
gcc 命令中,各个选项的含义是:
Linux 平台上,动态链接库文件的命名格式为 libxxx.so,其中 xxx 部分可以自定义。
我们也可以先将 myMath.c 编译为目标文件,然后再将目标文件转换为动态链接库,整个过程为:
实际上以上两种转换过程是一样的,直接将 myMath.c 转换成动态链接库的过程,底层也是先将 myMath.c 转换为 myMath.o,然后再将 myMath.o 转换为动态链接库。
由此,我们就成功地创建了动态链接库文件。
以刚刚生成的 libmyMath.so 为例,讲解 Linux 平台上如何将一个动态链接库文件引入到我们自己的项目中。
假设某个项目中仅有一个 main.c 文件,包含的代码如下:
#include <stdio.h>
int main() {
int a = 3, b = 4;
printf("a+b=%d\n", add(a, b));
printf("a-b=%d\n", sub(a, b));
printf("a*b=%d\n", mul(a, b));
printf("a/b=%d", div(a, b));
return 0;
}
显然,程序中用到了 libmyMath.so 动态链接库中的函数。执行以下两步,即可完成 main.c 和 libmyMath.so 的动态链接:
1) 将 main.c 与 myMath.h 放在同一目录,向 main.c 文件中引入 myMath.h 头文件:
2) 执行如下指令,即可生成可执行文件:
最终生成的 main.exe 就是可执行文件。
注意,main.exe 执行时需要将 libmyMath.so 一起载入内存,您运行 main.exe 时可能会遇到如下问题:
执行结果提示:main.exe 执行时无法找到 libmyMath.so 动态链接库。通过执行 ldd main.exe 指令,可以查看 main.exe 执行时需要调用的所有动态链接库,以及它们各自的存储位置:
可以看到,main.exe 执行时需要链接 4 个动态库文件,其中 libmyMath.so 文件的存储位置显示“not found”,是导致 main.exe 执行失败的直接原因。
运行由动态链接库生成的可执行文件时,必须确保程序运行时可以找到所有需要的动态链接库。常用的解决方案有如下几种:
例如选择第一种解决方案,将 libmyMath.so 移动到 /usr/lib 目录下,再次执行ldd main.exe指令:
重新执行 main.exe :
可以看到,main.exe 执行成功了,表明我们成功地将 libmyMath.so 引入到了自己的项目中。