-L -Wl,-rpath-link -Wl,-rpath区别精讲

2023-11-08

目录

 

前言

关于gcc这三个参数,参考了诸多文档后,仍然理解上有偏差,仿照下面博客中的方法,自己调试了一波,总算是理解了。还是建议大家动手实践一下。

参考资料如下:

源码准备

新建三个文件:test.c hello.c world.c ,其源码依赖关系为:test.c 依赖 hello.c;hello.c 依赖 world.c

源码内容

test.c

#include <stdio.h>
void world(void);
void hello(void)
{
    printf("hello ");
    world();
}

hello.c

#include<stdio.h>
void hello(void);
void main(void)
{
    hello();
}

world.c

#include<stdio.h>
void world(void)
{
	printf("world.\n");
}

尝试编译,保证源码没有问题

# -o 指定输出文件
[root@localhost testc]# ls
hello.c  test.c  world.c
[root@localhost testc]# gcc -o hehe *.c
[root@localhost testc]# ls
hehe  hello.c  test.c  world.c
[root@localhost testc]# ./hehe 
hello world.

编译

首先编译world.c

# -shared 编译链接库
# -fPIC 我的理解是编译链接库时给代码动态分配内存
[root@localhost testc]# gcc -shared -fPIC -o libworld.so world.c
[root@localhost testc]# ls
hello.c  libworld.so  test.c  world.c
[root@localhost testc]# ldd libworld.so 
	linux-vdso.so.1 =>  (0x00007ffd7498f000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fcb49815000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fcb49dea000)

#上述命令和下面的等价,建议选取单条命令即可:gcc -shared -fPIC -o libworld.so world.c
# -c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
[root@localhost testc]# gcc -c -fPIC world.c 
[root@localhost testc]# ls
hello.c  test.c  world.c  world.o
[root@localhost testc]# gcc -shared -fPIC -o libworld.so world.o
[root@localhost testc]# ls
hello.c  libworld.so  test.c  world.c  world.o
[root@localhost testc]# ldd libworld.so 
	linux-vdso.so.1 =>  (0x00007ffd0dfa9000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f4357dcb000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f43583a0000)

编译并链接hello.c

# -lxxx 指定需要动态链接的库文件
# -L 指定动态连接库文件的位置(编译时)
# . 指当前路径
# 下面编译出的libhello.so文件已经显式依赖libworld.so文件,但是没有找到libworld.so的位置
[root@localhost testc]# gcc -shared -fPIC -o libhello.so hello.c -lworld -L.
[root@localhost testc]# ls
hello.c  libhello.so  libworld.so  test.c  world.c
[root@localhost testc]# ldd libhello.so 
	linux-vdso.so.1 =>  (0x00007ffe61b89000)
	libworld.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007ff73cc1e000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ff73d1f4000)

调试编译test.c

[root@localhost testc]# ls
hello.c  libhello.so  libworld.so  test.c  world.c

# 编译出错,提示找不到hello
[root@localhost testc]# gcc -o haha test.c 
/tmp/ccQCWcSW.o: In function 'main':
test.c:(.text+0x5): undefined reference to 'hello'
collect2: error: ld returned 1 exit status

# 添加libhello.so的链接索引,并指定库的搜索路径为'.'(当前路径)
# 依然编译失败,提示找不到libworld.so,该库被libhello.so依赖,并提示建议使用-rpath 或 -rpath-link解决
[root@localhost testc]# gcc -o haha test.c -lhello -L.
/usr/bin/ld: warning: libworld.so, needed by ./libhello.so, not found (try using -rpath or -rpath-link)
./libhello.so: undefined reference to 'world'
collect2: error: ld returned 1 exit status

# 手动添加libworld.so的依赖,编译通过,查看haha的链接库,已经显式指出依赖,但是没有找到其位置
[root@localhost testc]# gcc -o haha test.c -lhello -L. -lworld
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007fff556ea000)
	libhello.so => not found
	libworld.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f1ff0c97000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f1ff106b000)

# 执行编译出的haha,执行报错,提示找不到依赖库
[root@localhost testc]# ./haha 
./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

#修改系统环境变量'LD_LIBRARY_PATH',增加索引库的位置,查看依赖OK,执行haha, 结果OK, 清空'LD_LIBRARY_PATH'
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/  && echo $LD_LIBRARY_PATH
/home/testc/
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007ffd647d2000)
	libhello.so => /home/testc/libhello.so (0x00007fb7aa063000)
	libworld.so => /home/testc/libworld.so (0x00007fb7a9e60000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fb7a9a8e000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fb7aa266000)
[root@localhost testc]# ./haha 
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=  && echo $LD_LIBRARY_PATH

# 将-lworld 替换为 -Wl,-rpath-link=. ,编译OK,依然找不到索引库,添加LD_LIBRARY_PATH后,执行OK 
[root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath-link=.
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007ffdf67c0000)
	libhello.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007fbdbb94b000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fbdbbd1f000)
[root@localhost testc]# ./haha 
./haha: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc  && echo $LD_LIBRARY_PATH
/home/testc
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007fff89504000)
	libhello.so => /home/testc/libhello.so (0x00007fc9e75c6000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fc9e71f3000)
	libworld.so => /home/testc/libworld.so (0x00007fc9e6ff1000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fc9e77c9000)
[root@localhost testc]# ./haha 
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=  && echo $LD_LIBRARY_PATH

# 将-Wl,-rpath-link=. 换成 -Wl,-rpath=. 编译OK, 查看链接库OK,执行OK 
# 修改LD_LIBRARY_PATH后,链接库的位置没有变化
[root@localhost testc]# gcc -o haha test.c -lhello -L. -Wl,-rpath=.
[root@localhost testc]# ls
haha  hello.c  libhello.so  libworld.so  test.c  world.c
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007fff86195000)
	libhello.so => ./libhello.so (0x00007f4c11254000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f4c10e81000)
	libworld.so => ./libworld.so (0x00007f4c10c7f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f4c11457000)
[root@localhost testc]# ./haha 
hello world.
[root@localhost testc]# export LD_LIBRARY_PATH=/home/testc/  && echo $LD_LIBRARY_PATH
/home/testc/
[root@localhost testc]# ldd haha 
	linux-vdso.so.1 =>  (0x00007ffc9f36c000)
	libhello.so => ./libhello.so (0x00007f35cf07c000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f35ceca9000)
	libworld.so => ./libworld.so (0x00007f35ceaa7000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f35cf27f000)
[root@localhost testc]# export LD_LIBRARY_PATH=  && echo $LD_LIBRARY_PATH


结论

  • 编译时链接库需要分为两类: 直接引用 间接引用
  • 直接引用 被源码中直接调用的库
  • 间接引用 被调用库的依赖库
  • -lxxx 指定具体的库名称,编译时需要显式指定直接引用的库名称
  • -L 指定链接库的位置,编译时需要显式指定直接引用的库位置
  • -Wl,-rpath-link ,用于编译时指定间接引用的库位置
    如果知道所有间接引用的库文件名称,并且不嫌麻烦,也可以用-lxxx显式指定每一个库(不推荐-lxxx)
  • -Wl,-rpath ,有两个作用:
    1. 用于编译时指定间接引用的库位置,作用同-Wl,-rpath-link
    2. 用于运行时指定所有引用库的位置,作用同修改环境变量(LD_LIBRARY_PATH),并且库路径引用优先级高于LD_LIBRARY_PATH
  • 使用建议
    1. 编译命令中使用-Wl,-rpath-link 指定间接引用库位置(编译时),使用-Wl,-rpath 指定引用库位置(运行时)
    2. -Wl,-rpath-link 在 -Wl,-rpath 前
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

-L -Wl,-rpath-link -Wl,-rpath区别精讲 的相关文章

  • c++编写消消乐游戏

    include
  • AR基础讲解:打造AR元宇宙博物馆编程之旅

    AR基础讲解 打造AR元宇宙博物馆编程之旅 随着技术的不断发展 增强现实 AR 正逐渐成为各个领域的热门技术 而在AR中 构建一个全新的虚拟世界 AR元宇宙博物馆 使我们能够透过手机或其他AR设备与数字内容进行互动 本文将为大家介绍如何使用
  • 美国病毒systemd占用100%,root密码登录卡死

    1 top 查看到有僵尸进程一直启动 2 lsof p 752 查看进程的来源 3 crontab l 查看定时任务 是否有自动启动
  • C语言网络编程(二)建立套接字通讯UDP

    所谓socket套接字 指的是在网络通信以前建立的通信接口 进行网络连接以前 需要向系统注册申请一个新的socket 然后使用这个socket进行网络连接 提示 套接字 传输层协议 端口号 IP地址 在进行网络连接以前 需要用socket函
  • 代码随想录算法训练营19期第57天

    647 回文子串 代码随想录 初步思路 动态规划 总结 dp i j 表示区间范围 i j 注意是左闭右闭 的子串是否是回文子串 当 s i s j 时 需要判断 dp i 1 j 1 是不是一个回文串 if s i s j j i lt
  • 3分钟搞懂js的冒泡和捕获?

    为了快速理解js冒泡和捕获 我们先看代码
  • 桌前检查、代码评审、走查

    桌前检查 Disk Checking 这是一种传统的检查方法 由程序员检查自己编写的程序 程序员在程序通过编译之后 进行单元测试之前 对源程序代码进行分析 检验 并补充相关的文档 目的是发现程序中的错误 检查项目有 1 检查变量的交叉引用表
  • 浅谈3NF(范式)建模

    范式 一张数据表的表结构所符合的某种设计标准的级别 构造数据库必须遵循一定的规则 在关系型数据库中 这种规则就是范式 范式是符合某一种级别的关系模式的集合 目前关系数据库有六种范式 第一范式 1NF 第二范式 2NF 第三范式 3NF 第四
  • Pycharm及python安装详细教程(图解)

    更多编程教程请到 菜鸟教程 https www piaodoo com 友情链接 好看站 http www nrso net 首先我们来安装python 1 首先进入网站下载 点击打开链接 或自己输入网址https www python o
  • java类是公共的应当声明,java 类是公共的,应在名为.java 的文件中声明

    java 类是公共的 应在名为 java 的文件中声明 关注 162 答案 2 mip版 解决时间 2021 01 16 12 24 提问者关系已逝 2021 01 15 16 19 import javax swing JOptionPa
  • ajax中中loaddate,jQuery中ajax的load()与post()方法实例详解

    本文实例讲述了jQuery中ajax的load 与post 方法 分享给大家供大家参考 具体如下 一 load 方法 在jQuery ajax的load 方法能够载入远程 HTML 文件代码并插入至 DOM 中 这个与post get还是有
  • 数据结构与算法(九)-- 队列

    队列 队列的定义 它只允许在表的前端 front 进行删除操作 而在表的后端 rear 进行插入操作 进行插入操作的端称为队尾 进行删除操作的端称为队头 顺序队 采用顺序存储结构的队列 存储空间连续 front指向对头元素 rear 指向队
  • 利用Dom4j创建xml文档

    DocumentHelper是使用Dom4j的辅助类的集合 利用它我们可以创建xml文档 接下来我们就使用它来创建一个简单的xml文档 创建文档 第一种方式 Document document DocumentHelper createDo
  • 20200317_决策树预测贷款申请

    使用决策树 预测贷款申请 import pandas as pd 忽略弹出的warnings import warnings warnings filterwarnings ignore text pd read excel data Lo
  • 前导0 的数字

    代码和任务 copyright c 2015 csdn学院 All right reserved 文件名称 main c 作者 张如田 完成日期 版本号 任务描述 输入小时和分 以hh mm形式输出 其中小时和分钟不足两位数时 用零前导 例
  • 手动下载Python第三方库whl文件并进行安装

    手动下载Python第三方库whl文件并进行安装 在Python开发中 我们经常需要使用第三方库来辅助我们完成各种任务 而通常在安装这些库时 我们会使用pip命令进行安装 但有时候因为网络环境等原因 pip无法正常工作 导致我们无法安装所需
  • Ubuntu上交叉编译opencv及opencv_contrib并移植到ARM板之一

    完整人脸识别系统 源码 教程 环境 开源毕业设计 基于嵌入式ARM Linux的应用OpenCV和QT实现的人脸识别系统 源码 论文 完全毕设教程 Linux上Opencv与Qt实现的人脸识别的考勤点名 门禁系统 PC与嵌入式ARM版本 零
  • I2C通信基本原理及其实现

    I2C是一种总线式结构 它只需要SCL时钟信号线与SDA数据线 两根线就能将连接与总线上的设备实现数据通信 由于它的简便的构造设计 于是成为一种较为常用的通信方式 由于I2C采用的是主从式通信方式 所以 通信的过程完全由主设备仲裁 在通信之
  • 蓝桥杯2019年第十届省赛真题-扫地机器人

    题目 题目链接 题解 二分 贪心 二分模板 看到这道题第一时间想到的就是二分和动规 仔细一看二分有戏 能check出来 所以决定用二分好好想想 主要是因为我动规太菜了 怕了 二分时间 准确的说我们二分的不是时间 而是覆盖范围 也就是枚举每个

随机推荐

  • 《Python编程:从入门到实践》学习笔记——第11章 测试代码

    文章目录 前言 1 测试函数 1 1 单元测试和测试用例 1 2 可通过的测试 1 3 不能通过的测试 1 4 测试未通过时怎么办 1 5 添加新测试 2 测试类 2 1 各种断言方法 2 2 一个要测试的类 2 3 测试 Anonymou
  • 【机器学习】随机森林预测并可视化特征重要性

    今天需要用到特征重要性的分析 所以干脆就写一下使用随机森林是如何做建模并基于随机森林做特征重要性的分析 顺带给出了编码方式 随机森林 特征重要性可视化的完整Python代码 都是可以直接运行的 目 录 1 分类型特征编码 1 1 Label
  • cmd 命令行显示中文乱码

    cmd命令行显示中文乱码多数是由于字符编码不匹配导致 1 查看cmd编码方式 方法一 打开cmd 输入chcp命令回车 显示默认编码 活动代码页 936指GBK 方法二 打开cmd在标题栏单击鼠标右键选择 属性 在属性选项中可看到当前编码方
  • JAVA的OPENGL,JOGL入门实例----不断变色的点阵 (源代码)

    原文 http blog csdn net sidihuo article details 44035015 第一个类 代码解读 java view plain copy package test1 opengl import java a
  • AirtestIDE学习笔记---安装(windows系统)

    这篇写的更详细点 https blog csdn net u013405658 article details 99443091 Airtest之前有听到过这样的工具 一直没有小试牛刀 直到上周参加了TesterHome社区组织的测试开发者
  • gTest 学习

    gTest 目录 在Clion上安装 断言 判断bool 数值判断 字符串判断 显示返回成功或失败 异常检查 输出更详细信息 自定义输出 浮点数相等 相近判断 事件 全局事件 TestSuite事件 TestCase事件 参数化 在Clio
  • 【mcuclub】STC89C52单片机最小系统讲解

    1 实物图 2 原理图 3 介绍 3 1 主芯片 STC89C52是STC公司生产的一种低功耗 高性能8位微控制器 器件参数 1 增强型8051单片机 指令代码完全兼容传统8051 2 工作电压 5 5V 3 3V 3 工作频率范围 0 4
  • 从零开始的管理系统(自用)之三:.NET6后端框架搭建和私人Nuget服务搭建

    因为既然采用前后端分离的方式 就不想把所有功能都写在一个项目里面 对电脑性能的debug都是一种负担 于是采用微服务思想 将后端API按照业务拆分 因为肯定不能的服务会用到相同的代码块 因此搭建私人Nuget包用来封装相同的代码块 1 vs
  • 【C++】error: passing ‘const xxx’ as ‘this’ argument discards qualifiers [-fpermissive]

    1 错误信息分析 error passing const xxx as this argument discards qualifiers fpermissive 直译 错误 将 const xxx 作为 this 参数传递会丢弃限定词 d
  • 绿色开源的屏幕/截屏OCR软件Capture2Text

    近日发现一个比较好的绿色开源的屏幕 截屏OCR软件 Capture2Text 官网说明 http capture2text sourceforge net 项目地址 https sourceforge net projects captur
  • 仿射密码实验 C语言

    文件操作 FILE fp fp fopen r 打开文件 while fgets msg 50 fp1 NULL 读取文件中的数据 50 1 长度 到 msg数组 fprintf fp d num 向文件格式输入 最后记得关闭文件 函数 求
  • 使用Maven+Intellij快速创建一个SpringBoot项目——helloworld

    文章目录 一 从 http start spring io 生成maven项目 二 导入maven项目 三 maven项目目录结构 四 创建controller 五 运行项目 springboot内置了tomcat服务器 这样在web项目中
  • JSONObject 比 Map好使的地方

    需求 改originalJson中的json字符串的key 当key满足在configMapping中配置的key2情况的时候 把originalJson的key改成 configMapping中的value2 上代码 import cn
  • 【C语言】快速排序

    一 算法描述 一个基准 两个指针 一个前指针 一个后指针 前指针负责比基准小的数 后指针负责比基准大的数 前指针向后移动的过程中如果遇到比基准大的数就停止移动 交换前后指针的值 后指针向前移动的过程中如果遇到比基准小的数就停止移动 交换前后
  • java imagemagick 接口_ImageMagick安装及使用教程

    ImageMagick是一套功能强大且免费的图片处理开发包 可以用来读 写和处理多种格式的图片文件 本节介绍下ImageMagick的安装与使用方法 1 imagemagick安装 以linux下源码安装为例 首先到ImageMagick官
  • VC 根据域名获取IP

    include Winsock2 h pragma comment lib Ws2 32 lib 注意字符串需以 0结尾 例如 lpzSeverName www baidu com 0 bool WINAPI Domain2IP char
  • 使用Matplotlib画出线形图的简单教程

    import matplotlib pyplot as plt import numpy as np ipython 画图 pylab inline In 10 简单线图 生成测试数据 x np linspace 1 1 50 y np c
  • 游戏社区App (六):文章编辑与上传

    一 文章编辑 Android端 示例 1 富文本编辑器 富文本编辑器参考的是GitHub上RichEditotAndroid的富文本编辑器 实现方式为使用 WebView JavaScript 原理为使用WebView来显示一个本地HTML
  • 数值千分位

    场景 如果数值超过1000会进行 进行分割 formatNumber num 将数字转换为字符串 并使用正则表达式匹配千分位位置 return String num replace d 1 3 d 3 d g 1
  • -L -Wl,-rpath-link -Wl,-rpath区别精讲

    目录 前言 源码准备 源码内容 尝试编译 保证源码没有问题 编译 首先编译world c 编译并链接hello c 调试编译test c 结论 前言 关于gcc这三个参数 参考了诸多文档后 仍然理解上有偏差 仿照下面博客中的方法 自己调试了