当前位置: 首页 > news >正文

-Wl,-rpath= 编译器链接器指定动态库路径 与 LD_LIBRARY_PATH

实例先行,

1,情景

三互相依赖的小项目:

(1)libbottom.so,无特别依赖,除系统文件

(2)libtop.so,依赖libbottom.so

(3)app 可执行程序,依赖libtop.so


2,具体实现及问题

2.1 bottom

bottom.cpp

//bottom.cpp
#include "bottom.h"
#include <stdio.h>int bottom(int a, int b)
{//printf("bottom() running\n");return a+b;}

bottom.h

//bottom.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endifint bottom(int a, int b);#ifdef __cplusplus
}
#endif

Makefile

LIB := libbottom.so%.o: %.cppg++ -fPIC $< -c -o $@$(LIB): bottom.og++ -shared $< -o $@.PHONY: clean
clean:-rm -rf $(LIB) *.o

需要留意 tab健

编译:

2.2 top

top.cpp

//top.cpp
#include "top.h"
#include <stdio.h>int top(int a, int b, int c)
{printf("top() running\n");return bottom(a, b) + c;}

top.h

//top.h
#pragma once#include "bottom.h"#ifdef __cplusplus
extern "C" {
#endifint top(int a, int b, int c);#ifdef __cplusplus
}
#endif


Makefile

LIB := libtop.soINC := -I ${'pwd'}../bottom/
LD_FLAGS := -L ${'pwd'}../bottom/ -lbottom
%.o: %.cppg++ -fPIC $< -c -o $@ $(INC) $(LD_FLAGS)$(LIB): top.og++ -shared $< -o $@.PHONY: clean
clean:-rm -rf $(LIB) *.o

编译:

2.3 app


hello_top_bottom.cpp

//hello_top_bottom.cpp
#include "top.h"
#include <stdio.h>
int main()
{int x = 3, y = 4, z = 5;int sum = 0;sum = top(x, y, z);printf("sum = %d\n", sum);return 0;
}


Makefile
 

EXE := hello_top_bottomall: $(EXE)INC := -I ${PWD}/../top/ -I ${PWD}/../bottom/
LD_FLAGS := -L ${PWD}/../top/ -ltop -L ${PWD}/../bottom/ -lbottom%: %.cppg++ $< -o $@ $(INC) $(LD_FLAGS).PHONY: clean
clean:-rm -rf $(EXE)

编译运行:

这种情况下,如何运行起来呢?

使用LD_LIBRARY_PATH 环境变量:

export LD_LIBRARY_PATH=../top/

此时能够找到 libtop.so,但是找不到 libbottom.so

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../bottom/

这时候可以找到 libbottom.so

 以上为常用方法。

3,回退问题

3.1 取消 LD_LIBRARY_PATH的赋值

export LD_LIBRARY_PATH=

这样,即使编译通过,又回到了找不到 libtop.so的状态:

3.2 构建 app时不链接 bottom 库

将 app/Makefile 修改为不链接 libbottom.so   :

EXE := hello_top_bottomall: $(EXE)INC := -I ${PWD}/../top/ -I ${PWD}/../bottom/
LD_FLAGS := -L ${PWD}/../top/ -ltop
#-L ${PWD}/../bottom/ -lbottom%: %.cppg++ $< -o $@ $(INC) $(LD_FLAGS).PHONY: clean
clean:-rm -rf $(EXE)

此时又回到了无法编译的状态:

提示 rpath,我们来试一下

3.3 对 top 使用 rpath

只修改 top/Makefile 为:

LIB := libtop.soINC := -I ${PWD}/../bottom/
LD_FLAGS := -L ${PWD}/../bottom/ -lbottom -Wl,-rpath=../bottom/%.o: %.cppg++ -fPIC $< -c -o $@ $(INC)#       $(LD_FLAGS)$(LIB): top.og++ -shared $< -o $@ $(LD_FLAGS).PHONY: clean
clean:-rm -rf $(LIB) *.o

然后再编译app,此时可以编译通过,但是依然不能运行:

此时配置 LD_LIBRARY_PATH,只需要配置 top 的路径,即可运行,不需要配置bottom的路径:

export LD_LIBRARY_PATH=../top/

 

其中,libtop.so 是靠 LD_LIBRARY_PATH 提供的线索找到的

而 libbottom.so 是靠 链接生成 libtop.so 时 指定的 -rpath 找到的。

4.0 如果指定rpath 的路径与 LD_LIBRARY_PATH 指向的路径不同

这个实验我们通过 top 依赖的 bottom 来进行,

准备另一份 libbottom.so:

当通过指定新的环境变量后

export LD_LIBRARY_PATH=/home/archer/ex_rpath/local:$LD_LIBRARY_PATH

发现top通过rpath指向的libbottom.so 被 LD_LIBRARAY_PATH        取代。

5.  通过分析 readelf -d libtop.so

在gcc 11 中,只有RUNPATH,

原因:

在一些情况下,特别是在较新版本的 GCC 中(如 GCC 11),生成的 ELF 文件可能会只包含 RUNPATH 而不包含 RPATH。这是因为 RUNPATH 是一种更加灵活和推荐的方式来指定运行时库的搜索路径,相比之下,RPATH 的使用可能存在一些安全和可维护性上的问题。

主要区别在于:

  • RPATH 是在链接时硬编码到 ELF 文件中的搜索路径,优先级低于系统默认路径和 LD_LIBRARY_PATH 环境变量。
  • RUNPATH 也是指定运行时库的搜索路径,但优先级高于系统默认路径和 LD_LIBRARY_PATH 环境变量,且可以被覆盖。

因此,如果你在使用 GCC 11 生成的 ELF 文件中只看到 RUNPATH 而没有 RPATH,这是符合最新标准和最佳实践的做法。RUNPATH 提供了更灵活和可控的方式来管理共享库的搜索路径,有助于提高系统的安全性和可维护性。

6,运行时搜索 libxx.so 的优先级

搜索.so的优先级顺序

1.    RPATH: 本信息由 elf 文件提供
2.   LD_LIBRARY_PATH: 这是环境变量
3.   RUNPATH:本信息也由 elf 文件提供
4.    ldconfig的缓存: 通过配置/etc/ld.conf*来修改
5.    默认的系统路径:/lib, /usr/lib

故,通过LD_LIBRARY_PATH 提供的路径中的 libbottom.so 会优先被搜索到。

7,-Wl,rpath-link

-Wl,rpath-link 是设置编译链接时候的搜索顺序,格式跟rpath 的设置一样,而rpath 是设置运行时的搜索顺序;

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 期末九天从入门到精通操作数据库(mysql)
  • 猫头虎 分享:Python库 SymPy 的简介、安装、用法详解入门教程 ‍
  • 鹏城杯 2022 取证writeup
  • OD C卷 - 结对编程
  • 计算机毕业设计 高校学术交流平台 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • python实用教程(二):安装配置Pycharm及使用(Win10)
  • 【MySQL】 黑马 MySQL进阶 笔记
  • 解决 VMware 中 Ubuntu文件系统磁盘空间不足
  • 【Leetcode 1832 】 判断句子是否为全字母句 —— 忙忙碌碌哈希表不如一行代码速度快
  • Object.create的原型继承
  • [笔记] hyperf event
  • Html中嵌入module类型的JavaScript代码,如何访问其中的函数或变量?
  • 数论之高斯消元
  • Spring父子容器
  • 文心快码 Baidu Comate 前端工程师观点分享:以文心快码 Baidu Comate为例,智能代码助手需要什么(三)
  • @angular/forms 源码解析之双向绑定
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 【附node操作实例】redis简明入门系列—字符串类型
  • css布局,左右固定中间自适应实现
  • CSS中外联样式表代表的含义
  • HTML5新特性总结
  • javascript面向对象之创建对象
  • js ES6 求数组的交集,并集,还有差集
  • Median of Two Sorted Arrays
  • React Native移动开发实战-3-实现页面间的数据传递
  • spark本地环境的搭建到运行第一个spark程序
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • 阿里云前端周刊 - 第 26 期
  • 基于web的全景—— Pannellum小试
  • 离散点最小(凸)包围边界查找
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 两列自适应布局方案整理
  • 区块链技术特点之去中心化特性
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • ​HTTP与HTTPS:网络通信的安全卫士
  • ​决定德拉瓦州地区版图的关键历史事件
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • #70结构体案例1(导师,学生,成绩)
  • #include
  • #php的pecl工具#
  • #在 README.md 中生成项目目录结构
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (2015)JS ES6 必知的十个 特性
  • (CPU/GPU)粒子继承贴图颜色发射
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (一)appium-desktop定位元素原理
  • (一)认识微服务
  • (转)IOS中获取各种文件的目录路径的方法
  • (转)mysql使用Navicat 导出和导入数据库