linux下封装函数库——动态库.so和静态库.a(代码实现及链接方式)

简介: 在linux环境下的链接库分为静态链接库(.a库)和动态链接库(.so库),其作用是把C程序编译好做成一种可执行链接文件,主程序文件调用这些程序的函数接口是可以使用a库或so库,在主程序中只需要include含有库中提供的函数接口声明的头文件即可。所以学会如何将自己的源代码封装成库进行使用很重要

在linux环境下的链接库分为静态链接库(.a库)和动态链接库(.so库),其作用是把C程序编译好做成一种可执行链接文件,主程序文件调用这些程序的函数接口是可以使用a库或so库,在主程序中只需要include含有库中提供的函数接口声明的头文件即可。所以学会如何将自己的源代码封装成库进行使用很重要,接下来就来介绍一下然后进行库的封装:

1、动态链接库的制作:

首先,生成一个简单的函数实现mymax(a,b),将它封装成库来进行举例:

代码如下:


1 int mymax(int a, int b)
  2 {
  3     if(a > b)
  4         return a;
  5     return b;
  6 }

             


这里可以通过gcc命令才生成.so库,也可以编写Makefile生成so库,Makefile如下:

1 CC = gcc
  2 SRCS = mymax.c
  3 OBJS = $(SRCS:.c=.o)
  4 EXEC = libmymax.so//这里要注意生成的库文件开头必须lib开头,后缀.so
  5 start:$(OBJS)
  6         $(CC) -o $(EXEC) $(OBJS) -shared//这表明是一个动态库
  7 .c.o:
  8         $(CC) -o $@ -c $< -fPIC//表示编译函数时没有偏移地址
  9 clean:
 10         rm -rf $(OBJS)



当然也可以直接使用指令:

20180916094638826.png

这里一定要注意so库的前缀必须为lib,然后将.so库链接到主程序main.c中,这里需要注意一下,因为动态库的特性,编译器会到指定的目录去寻找动态库,目录的地址在/etc/ld.so.conf.d/ 目录里的libc.conf文件里,你可以在里面加一行地址表示你so库的位置,更改完conf文件里的内容,记得输入命令行:ldconfig。

你还可以将so库复制到默认的目录下。这里是将so库复制到了默认目录下,生成可执行文件并运行,最后进行编译链接使用Makefile如下:

1 CC = gcc
  2 SRCS = mylib.c
  3 OBJS = $(SRCS:.c=.o)
  4 EXEC = myapp
  5 start:$(OBJS)
  6         $(CC) -o $(EXEC) $(OBJS) -L. -lmymax
  7 .c.o:
  8         $(CC) -o $@ -c $< 
  9 clean:
 10         rm -rf $(OBJS)



这样就生成了可执行程序myapp,

注意:在加载动态链接库的时候,有可能会遇到加载不到的错误,原因在于系

统默认加载的动态链接库路径里没有找到你的动态库,有三种解决方法:

**1.在执行gcc main.c -L. -ltest -o main 前,执行 export **

LD_LIBRARY_PATH=$(pwd)

2.将你so所在的目录写到/etc/ld.so.conf文件里,然后执行ldconfig。

3.将你的so放在/etc/ld.so.conf里的路径位置里。


最后可以通过指令ldd查看执行程序的链接库都有哪些:

20180916095257327.png

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

接下来制作静态链接库:

20180916100211500.png

最后使用nm命令可以查看程序依赖的库信息:

20180916100524144.png从中可以找到我们进行链接的静态库信息。


最后,如果对其他一些细节还需要详细了解的话,推荐一个博客,我觉得写得真的很相信,http://www.cnblogs.com/skynet/p/3372855.html


加载动态库需要指定路径的问题

gcc中的rpath参数可以用编译时指定动态库的搜索路径,这样运行时就不需要export LD_LIBRARY_PATH了。

解决方案


  • 方案一

编译时增加参数-Wl,-rpath=’.’


可执行程序运行时会搜索当前工作目录(不是进程所在目录),所以如果在其它目录运行该可执行程序时会提示找不到动态库(同样,如果建立一个软连接ln -s时,也会提示找不到动态库)。


  • 方案二

编译时增加参数-Wl,-z,origin -Wl,-rpath=’$ORIGIN’


O R I G I N 表 示 会 搜 索 进 程 所 在 目 录 ( 同 样 也 可 以 设 置 − r p a t h = ’ ORIGIN表示会搜索进程所在目录(同样也可以设置-rpath=’ORIGIN表示会搜索进程所在目录(同样也可以设置−rpath=’ORIGIN/lib’)。此方案不会出现方案一中软链接找不到动态库的情况。


  • 补充

通常情况下使用第二种方案是比较理想的,但是为了防止提升权限的漏洞,一旦进行了提升权限操作(比如chown root ping ;chmod u+s ping),则ORIGIN的设置会失效,运行可执行程序,会提示找不到动态库,即使使用export LD_LIBRARY_PATH设置了路径也无效。


要解决此问题:


  • 使用绝对路径(此方案不可取,所以没有亲自试验,应该是-rpath时指定绝对路径)
  • 将所依赖的so文件拷贝到操作系统默认会搜索的目录下,比如/lib或者/lib64等目录

查看编译好的动态库或者进程的rpath的方法

linux
readelf -d xxx.lib
solaris
greadelf -d xxx.lib


动态库的搜索路径的顺序

编译目标代码时指定的动态库搜索路径;
环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径;
配置文件 /etc/ld.so.conf 中指定的动态库搜索路径;
默认的动态库搜索路径 /lib ;
默认的动态库搜索路径 /usr/lib


大家共同进步

20180916100944502.jpg

相关文章
|
4天前
|
Linux 数据处理 开发者
Linux命令ld.bfd:二进制文件的强大链接器
`ld.bfd`是GNU链接器的变体,利用BFD库处理多种目标文件格式(如ELF, COFF)。它收集文件,解析符号,执行重定位,生成可执行文件。特点包括多格式支持,高效符号管理和诊断信息。常用命令如`ld.bfd -o output file1.o file2.o -lc`。注意文件路径、链接顺序,利用诊断信息和文档,保持工具更新以优化使用。
|
4天前
|
Linux 编译器 数据处理
探索Linux中的`ld`命令:链接器的奥秘
`ld`是Linux中的链接器,将编译后的目标文件链接成可执行或共享库。作为GNU Binutils的一部分,它处理符号引用、重定位,支持多种文件格式和库类型。常用参数包括`-o`指定输出文件,`-l`链接库,`-L`指定搜索路径。编译器驱动程序常用于简化链接过程。理解符号解析、选择静态/动态链接及管理库版本是使用`ld`的关键。使用`--verbose`调试链接问题,并考虑优化选项。
|
4天前
|
Linux 编译器 数据处理
深入了解Linux命令ld.gold:快速链接器的奥秘
`ld.gold`是GNU的快速链接器,设计用于加速大型项目的链接,尤其擅长并行处理和增量链接。它与标准的`ld`高度兼容,可通过`-fuse-ld=gold`选项启用。例如,`gcc -o my_program file1.c file2.c file3.c -Wl,--ld-as-needed -fuse-ld=gold`命令使用`ld.gold`链接多个源文件。最佳实践包括确保环境支持、利用多线程和启用增量链接。
|
1天前
|
Shell Linux 网络安全
Linux怎样在使用ssh 链接时就指定gcc 的版本
Linux怎样在使用ssh 链接时就指定gcc 的版本
16 7
|
17小时前
|
Linux vr&ar C语言
Linux怎样更新Centos下Gcc版本支持C17?Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理)
Linux怎样更新Centos下Gcc版本支持C17?Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理)
8 2
|
17小时前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
9 1
|
1天前
|
数据可视化 网络协议 Linux
Linux 怎样通过win 远程桌面连接链接Linux后台服务器的可视化图形界面
Linux 怎样通过win 远程桌面连接链接Linux后台服务器的可视化图形界面
8 0
|
1天前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
7 0
|
4天前
|
Linux 编译器 数据处理
探索Linux中的`ld`命令:链接器的奥秘
`ld`是Linux的链接器,集成在GNU Binutils中,将.o文件与库合并成可执行或共享库。它处理符号引用、重定位,支持多种文件格式及静态/动态链接。常用参数包括-o指定输出,-l和-L添加库和搜索路径。通常通过编译器驱动程序如gcc调用以简化链接过程。理解符号解析、选择静态/动态链接及管理库版本是使用ld的关键。使用--verbose选项有助于调试。
|
存储 Ubuntu Linux
【Linux】Python代码模块化
在目录下创建py文件,并进行运行任务要点:python的os和sys系统接口,文件接口
98 0
【Linux】Python代码模块化