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

2024-08-21 09:20

本文主要是介绍-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 是设置运行时的搜索顺序;

这篇关于-Wl,-rpath= 编译器链接器指定动态库路径 与 LD_LIBRARY_PATH的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092760

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

hdu2544(单源最短路径)

模板题: //题意:求1到n的最短路径,模板题#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#i

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

poj 1734 (floyd求最小环并打印路径)

题意: 求图中的一个最小环,并打印路径。 解析: ans 保存最小环长度。 一直wa,最后终于找到原因,inf开太大爆掉了。。。 虽然0x3f3f3f3f用memset好用,但是还是有局限性。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#incl

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

【408DS算法题】039进阶-判断图中路径是否存在

Index 题目分析实现总结 题目 对于给定的图G,设计函数实现判断G中是否含有从start结点到stop结点的路径。 分析实现 对于图的路径的存在性判断,有两种做法:(本文的实现均基于邻接矩阵存储方式的图) 1.图的BFS BFS的思路相对比较直观——从起始结点出发进行层次遍历,遍历过程中遇到结点i就表示存在路径start->i,故只需判断每个结点i是否就是stop

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

遮罩,在指定元素上进行遮罩

废话不多说,直接上代码: ps:依赖 jquer.js 1.首先,定义一个 Overlay.js  代码如下: /*遮罩 Overlay js 对象*/function Overlay(options){//{targetId:'',viewHtml:'',viewWidth:'',viewHeight:''}try{this.state=false;//遮罩状态 true 激活,f

Jenkins构建Maven聚合工程,指定构建子模块

一、设置单独编译构建子模块 配置: 1、Root POM指向父pom.xml 2、Goals and options指定构建模块的参数: mvn -pl project1/project1-son -am clean package 单独构建project1-son项目以及它所依赖的其它项目。 说明: mvn clean package -pl 父级模块名/子模块名 -am参数