SO动态链接库文件的编译和使用

Posted 我想月薪过万

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SO动态链接库文件的编译和使用相关的知识,希望对你有一定的参考价值。

做C语言开发的都知道,在Linux环境中动态链接库以 .so结尾;在Windows环境中动态链接库以 .dll结尾。在讲使用之前,我先来给大家补补基础。

链接库分为 静态链接库动态链接库。

静态链接库(a库):在 编译 的时候,库函数中函数的定义已经编译到源文件中,所以,静态链接库在编译完之后存不存在无关紧要。

动态链接库(so库):在 编译 的时候,库函数中函数的定义没有编译到源文件中,只是指定了库文件的路径,所以,编译之后源文件的执行还是依赖于so库文件。

静态链接库和动态链接库的区别在于,主程序在运行前,静态链接库的链接固定写入在程序中,而动态链接库则是在每次程序运行再加载链接。

如果对C语言编译 四步走 不熟悉的同学可以参考这篇文章 :微观的C/C++编译执行过程

在实际开发过程中,动态链接库用的居多,所以,我下面仅讲其的使用步骤:

代码示例

准备一个 .c 库函数文件

#include<stdio.h>
#include<stdlib.h>

int wust_test(int value){
    printf("%d\\n",value);
}

在这里我建议大家也写一个 .h 文件,也就是你这个库函数里面包含 函数的一个申明,这样函数的含义 和 用法便一目了然了。如下:

//功能:测试 so 动态链接库
//参数一:整型 
int wust_test(int value);

将这个库函数编译成 so 动态链接库

gcc test.c  -fPIC -shared -o libtest.so

gcc 依赖库文件 -fPIC -shared -o libxxx.so

libxxx.so 必须以 lib 开头 .so结尾

-fPIC       作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
  则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
  位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

-shared     目的是使源码编译成动态库 .so 文件

这个时候 so动态链接库 就生成了,下面我们来看看调用

编写 main.c 文件

#include<stdio.h>
#include<stdlib.h>

int wust_test(int value);

int main(){
    wust_test(33);
    return 0;
}

编译 main.c 文件

gcc main.c -o main -L. -ltest

-L 指定依赖库文件所在的目录

-l 指定依赖库 libtest.so --> -ltest

执行 main

./main

这个时候你会发现报错:大概意思就是找不到库文件。解决方法如下:

将 so动态链接库文件路径赋值给环境变量 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$(pwd): 

LD_LIBRARY_PATH:环境变量
pwd:当前目录的路径
::分隔符

再运行就可以了 

SO文件调用原理回顾

       大家看到这里就可以发现,动态链接库的创建和使用其实并不难。下面我将为大家梳理一下其中的思路。

       我们在编写 main.c 的时候可以看到,和普通的 main.c 没太大区别,关键点在于 wust_test() 这个方法没实现;那这怎么办呢?动态链接库就起作用了。我们将 动态链接库文件所在路径 配置给 环境变量 LD_LIBRARY_PATH,所以,当系统在找 wust_test() 方法的实现的时候,就会找到这个库,所以请注意:你不配置是找不到滴。在编译的时候,我们也用到了动态链接库,-L指定库文件路径,-l指定库文件,你不指定也会报错。

以上是关于SO动态链接库文件的编译和使用的主要内容,如果未能解决你的问题,请参考以下文章

linux 下如何将动态链接库.so进行反编译后,换编译器重新编译?

ELF 动态链接 - so 的 重定位表

LLINUX GCC 编译C使用自定义动态链接库.so的问题

Linux 动态链接库(.so)的使用

Linux下gcc编译生成动态链接库*.so文件并调用它转载

Linux gcc/g++编译链接头文件和库(动态库.so 和 静态库.a)