Linux下程序库制作方法详解

本文介绍了如何在Linux系统中使用GCC工具创建静态库和共享库,包括参数解释、创建步骤及调用方法。同时,文章也讨论了动态加载库的概念,涉及dlopen、dlsym和dlclose等函数,并提到了解决找不到库文件错误的方法,如修改LD_LIBRARY_PATH或编辑/etc/ld.so.conf。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家好,继上节<Linux库详解>,这节我们继续讲解如何在Linux系统上创建我们需要的库文件

  • 在创建程序库之前,需要先来了解GCC的一些参数,因为静态库和共享库需要GCC工具产生,并且两者的GCC参数不同。
参数含义
-c激活预处理、编译和汇编,把程序做成目标文件(.o文件)
-g在编译的时候产生调试信息
-Wall生成警告信息
-l指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
-L表示要连接的库目录
-fPIC表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方
-shared生成动态链接库

我们编写两个函数并将文件制作成库文件,用下面相同的代码分别制作静态库和共享库

Test.h文件

#ifndef _TEST_H_ 
#define _TEST_H_  

int add(int a, int b);
int sub(int a, int b);

#endif

Test.c文件

#include <stdio.h>
#include "Test.h"

int add(int a, int b)
{
    return (a+b);
}

int sub(int a, int b)
{
    return (a - b);
}

制作静态库

    1. 首先生成.o目标文件
gcc -c Test.c

在这里插入图片描述

    1. ar命令将目标文件生成.a静态库文件
ar -cr libTest.a Test.o // 遵循静态库命名的规则 lib + 名字 + .a

-c create的意思
-r replace的意思,表示当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。

在这里插入图片描述

    1. 静态库调用
#include <stdio.h>

#include "Test.h"

int main(int argc, char const *argv[])
{
    int nAdd = add(1, 2);
    printf("nAdd: %d\n", nAdd);

    int nSub = sub(2, 1);
    printf("nSub: %d\n", nSub);

    return 0;
}

gcc -o main main.c -lTest -L.

-l 指定了静态函数库名,由于静态函数库的命名方式是lib***.a,其中的lib和.a忽略
-L 指定静态函数库的查找目录,L后面’.',表示静态函数库在本目录下查找

在这里插入图片描述

制作共享库

  • 生成共享库
// 用下面两个命令
gcc -fPIC -o libTest.o -c Test.c
gcc -shared -o libTest.so libTest.o

// 或用下面一个命令
gcc -shared -fpic -o libTest.so Test.c

-fpic:产生位置无关代码
-shared:生成共享库

在这里插入图片描述

  • 共享库调用
#include <stdio.h>

#include "Test.h"

int main(int argc, char const *argv[])
{
    int nAdd = add(1, 2);
    printf("nAdd: %d\n", nAdd);

    int nSub = sub(2, 1);
    printf("nSub: %d\n", nSub);

    return 0;
}

gcc -o main-so main-so.c -lTest -L.

在这里插入图片描述

  • 执行可执行程序

在执行可执行程序时,出现以下错误,说找不到库文件,在继续往下看之前大家想想这是为什么?
在这里插入图片描述

因为在动态函数库使用时,会查找/usr/lib、/lib目录下的动态函数库,而此时我们生成的库不在里边。这是我们可以通过以下方法解决此问题,其实这个问题在上一节中我们提到过,小伙伴可以会看一下。

1.最直接最简单的方法就是把libTest.so拷贝到/usr/lib或/lib中去。

2.设置环境变量,假设libTest.so在/home/ubuntu/workspace_ex/lib/static目录下

export LD_LIBRARY_PATH=/home/linux/addsub:$LD_LIBRARY_PATH

3.另外还可以在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig
/etc/ld.so.conf是非常重要的一个目录,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从/usr/lib /lib中读取的,所以想要顺利运行,我们也可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig

在这里插入图片描述

动态加载库

上面共享库的调用属于动态链接方法,此外我们还可以动态加载,在上一节中我们讲过二者的区别,此处不做过多讲解。动态加载需要用到系统API函数

接口描述
dlopen打开对象文件,可被程序访问
dlsym获取执行了dlopen函数的对象文件中的符号的地址
dlerror返回上一次出现的错误
dlclose关闭目标文件

调用过程

#include <stdio.h>
#include <dlfcn.h>

#include"Test.h"

int main(int argc, char const *argv[])
{
    void *dlHandler = NULL;
    int(*Func)(int,int);
    char *Error;
    int  nAdd;

    dlHandler = dlopen("libTest.so", RTLD_LAZY);
    if(!dlHandler)
    {
        printf("dlopen:%s\n", dlerror());
        return 0;
    }

    Func = dlsym(dlHandler, "add");

    Error = dlerror();
    if(Error != NULL)
    {
        printf("find:%s\n",Error);
        return 0;
    }

    nAdd = (*Func)(1, 2);
    printf("add = %d\n",nAdd);

    dlclose(dlHandler);
    return 0;
}
gcc -o main-dl main-dl.c -ldl

在这里插入图片描述

-ldl 表明将 dllib 链接于该程序,即可调用DL的API

共享库文件放置于共享库调用时操作一样

结束语

到目前为止,我们详细讲解了Linux下制作静态库、共享库、以及动态加载库,希望通过此文对你在Linux库的认识有所帮助,那么目的就达到了

  • 如果感觉文章对你有一点帮助,关注点个赞呗,原创不易,支持一下,谢谢
  • 更多干货文章请关注公一(众)一号Linux兵工厂,并领取海量Linux学习资料
  • 👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇点击下方名片,领取海量Linux学习资料👇👇👇👇👇👇👇👇
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux兵工厂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值