热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

gcc使用Wl,rpath解决so库版本冲突

ref:https:www.dyxmq.cnlinuxgcc-option-wl-rpath.html一、问题描述最近工作中遇到了一个问题:项目需要合入其他部门的

ref:https://www.dyxmq.cn/linux/gcc-option-wl-rpath.html

一、 问题描述

最近工作中遇到了一个问题:项目需要合入其他部门的模块,但是其中的一个共用共享库被更新了。因为项目很大,如果直接在我们的环境中替换更新这个库,很有可能会影响到其他模块。祖传的代码流传了差不多20年,涉及的模块也十分之多,贸然升级的风险很难评估。但是不替换这个库第三方模块又跑不起来,一度头痛。

刚开始是想到了以下几 个方法:

1. 设置LD_LIBRARY_PATH环境变量,修改查找路径的优先级。

2. 修改so库名

对于第一种方法是有效的:在程序目录下加个lib目录,然后export LD_LIBRARY_PATH把当前路径放到第一搜索顺序,能解决这个问题。但是,环境变量时当前所有程序共享的,其他程序的搜索目录也是这里第一,所以这里的结果就和直接升级库没有区别。同样,修改/etc/ld.so.conf的原理也是一样。

第二种方法本来是认为比较靠谱的,但是测试发现共享库并不是根据文件名来的,修改库名无效。so库内部还有个真实的名字,可以通过 readelf -d lib*.so 来查看:

> readelf /usr/lib/libau.so -d Dynamic section at offset 0x2c88 contains 29 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libdl.so.2] 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000e (SONAME) Library soname: [libau.so.2]

1

2

3

4

5

6

7

8

> readelf /usr/lib/libau.so -d

 

Dynamic section at offset 0x2c88 contains 29 entries:

Tag Type Name/Value

0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]

0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]

0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

0x000000000000000e (SONAME) Library soname: [libau.so.2]

所以上面两种方法就被排除了,后面查了很久也没有找到合适的办法,崩溃。。。

最后去请教大佬就被告知了可以使用 -Wl,-rpath 选项来解决这个问题,试了一下确实可以。

二、-Wl,-rpath和-Wl,-rpath-link选项


2.1 -Wl,-rpath

加上 -Wl,-rpath 选项的的作用就是指定“程序运行时”的库搜索目录,是一个链接选项,生效于设置环境变量之前。

我们已经知道,共享库的查找顺序为:

1. LD_LIBRARY_PATH 环境变量的目录

2. ld.so.conf 高速缓冲文件中的目录

3. 系统的默认库目录如 /lib, /lib64

-Wl,-rpath 可以让程序在第一步搜索之前先搜索它所指定的目录,通过一个例子来说明:

// add.h int add(int i, int j); // add.c #include "add.h" int add(int i, int j) { return i + j; } // main.c #include #include "add.h" int main() { printf("1 + 2 = %d\n", add(1, 2)); return 0; }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// add.h

int add(int i, int j);

 

// add.c

#include "add.h"

 

int add(int i, int j) {

return i + j;

}

 

// main.c

#include

#include "add.h"

 

int main() {

printf("1 + 2 = %d\n", add(1, 2));

return 0;

}

add.h和add.c用于生成一个so库,实现了一个简单的加法,main.c中引用共享库计算1 + 2:

# 编译共享库 gcc add.c -fPIC -shared -o libadd.so # 编译主程序 gcc main.o -L. -ladd -o app

1

2

3

4

# 编译共享库

gcc add.c -fPIC -shared -o libadd.so

# 编译主程序

gcc main.o -L. -ladd -o app

编好后运行依赖库:

> ldd app linux-vdso.so.1 (0x00007ffeb23ab000) libadd.so => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007febb7dd0000) /lib64/ld-linux-x86-64.so.2 (0x00007febb83d0000 > ./app ./app: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory

1

2

3

4

5

6

7

> ldd app

linux-vdso.so.1 (0x00007ffeb23ab000)

libadd.so => not found

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007febb7dd0000)

/lib64/ld-linux-x86-64.so.2 (0x00007febb83d0000

> ./app

./app: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory

可以看到,libadd.so这个库是没有找到的,程序也无法运行,要运行它必须要把当前目录加到环境变量或者库搜索路径中去。

但是如果在链接的时候加上 -Wl,-rpath 选项之后:

> gcc -Wl,-rpath=`pwd` main.o -L. -ladd -o app > ldd app linux-vdso.so.1 (0x00007fff8f4e3000) libadd.so => /data/code/c/1-sys/solib/libadd.so (0x00007faef8428000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faef8030000) /lib64/ld-linux-x86-64.so.2 (0x00007faef8838000) > ./app 1 + 2 = 3

1

2

3

4

5

6

7

8

> gcc -Wl,-rpath=`pwd` main.o -L. -ladd -o app

> ldd app

linux-vdso.so.1 (0x00007fff8f4e3000)

libadd.so => /data/code/c/1-sys/solib/libadd.so (0x00007faef8428000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faef8030000)

/lib64/ld-linux-x86-64.so.2 (0x00007faef8838000)

> ./app

1 + 2 = 3

依赖库的查找路径就找到了,程序能正常运行。

2.2 -Wl,rpath-link

-Wl,rpath-link 是设置编译链接时候的顺序,例如app运行依赖libadd.so,但是libadd.so又依赖libadd_ex.so,rpath-link 就是指定libadd_ex.so的路径。和 -Wl,rpath 相比工作的时间不同,一个在链接期间,一个在运行期间。


推荐阅读
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
author-avatar
清晨竹林9_877
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有