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

实例先行,

1,情景

三互相依赖的小项目:

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

(2)libtop.so依赖libbottom.so

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

2,具体实现及问题

2.1 bottom

bottom.cpp

cpp 复制代码
//bottom.cpp
#include "bottom.h"
#include <stdio.h>

int bottom(int a, int b)
{
    //printf("bottom() running\n");
    return a+b;}

bottom.h

cpp 复制代码
//bottom.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif

int bottom(int a, int b);

#ifdef __cplusplus
}
#endif

 

Makefile

bash 复制代码
LIB := libbottom.so

%.o: %.cpp
    g++ -fPIC $< -c -o $@

$(LIB): bottom.o
    g++ -shared $< -o $@

.PHONY: clean
clean:
    -rm -rf $(LIB) *.o

需要留意 tab健

编译:

2.2 top

top.cpp

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

cpp 复制代码
//top.h
#pragma once

#include "bottom.h"

#ifdef __cplusplus
extern "C" {
#endif

int top(int a, int b, int c);

#ifdef __cplusplus
}
#endif

Makefile

bash 复制代码
LIB := libtop.so

INC := -I ${'pwd'}../bottom/
LD_FLAGS := -L ${'pwd'}../bottom/ -lbottom
%.o: %.cpp
    g++ -fPIC $< -c -o $@ $(INC) $(LD_FLAGS)

$(LIB): top.o
    g++ -shared $< -o $@

.PHONY: clean
clean:
    -rm -rf $(LIB) *.o

编译:

2.3 app

hello_top_bottom.cpp

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

cpp 复制代码
EXE := hello_top_bottom

all: $(EXE)

INC := -I ${PWD}/../top/ -I ${PWD}/../bottom/
LD_FLAGS := -L ${PWD}/../top/ -ltop -L ${PWD}/../bottom/ -lbottom


%: %.cpp
    g++ $< -o $@ $(INC) $(LD_FLAGS)

.PHONY: clean
clean:
    -rm -rf $(EXE)

编译运行:

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

使用LD_LIBRARY_PATH 环境变量:

bash 复制代码
export LD_LIBRARY_PATH=../top/

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

bash 复制代码
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../bottom/

这时候可以找到 libbottom.so

以上为常用方法。

3,回退问题

3.1 取消 LD_LIBRARY_PATH的赋值

bash 复制代码
export LD_LIBRARY_PATH=

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

3.2 构建 app时不链接 bottom 库

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

bash 复制代码
EXE := hello_top_bottom

all: $(EXE)

INC := -I ${PWD}/../top/ -I ${PWD}/../bottom/
LD_FLAGS := -L ${PWD}/../top/ -ltop
#-L ${PWD}/../bottom/ -lbottom


%: %.cpp
        g++ $< -o $@ $(INC) $(LD_FLAGS)

.PHONY: clean
clean:
        -rm -rf $(EXE)

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

提示 rpath,我们来试一下

3.3 对 top 使用 rpath

只修改 top/Makefile 为:

bash 复制代码
LIB := libtop.so

INC := -I ${PWD}/../bottom/
LD_FLAGS := -L ${PWD}/../bottom/ -lbottom -Wl,-rpath=../bottom/

%.o: %.cpp
        g++ -fPIC $< -c -o $@ $(INC)

#       $(LD_FLAGS)

$(LIB): top.o
        g++ -shared $< -o $@ $(LD_FLAGS)

.PHONY: clean
clean:
        -rm -rf $(LIB) *.o

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

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

bash 复制代码
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 会优先被搜索到。

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

相关推荐
九圣残炎31 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu37 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!1 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
为什么这亚子2 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
2 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
~yY…s<#>2 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
幸运超级加倍~3 小时前
软件设计师-上午题-16 算法(4-5分)
笔记·算法
yannan201903133 小时前
【算法】(Python)动态规划
python·算法·动态规划
埃菲尔铁塔_CV算法3 小时前
人工智能图像算法:开启视觉新时代的钥匙
人工智能·算法