-L -Wl,-rpath-link -Wl,-rpath區別精講

来源:https://www.cnblogs.com/tianknight/archive/2019/04/03/10648021.html
-Advertisement-
Play Games

-L -Wl,-rpath-link -Wl,-rpath區別精講 ...


目錄

轉載請註明出處,謝謝 https://www.cnblogs.com/tianknight/p/10648021.html

前言

關於gcc這三個參數,參考了諸多文檔後,仍然理解上有偏差,仿照下麵博客中的方法,自己調試了一波,總算是理解了。還是建議大家動手實踐一下。

參考資料如下:

  • https://blog.csdn.net/q1302182594/article/details/42102961
  • https://blog.csdn.net/openme_openwrt/article/details/7860580

源碼準備

新建三個文件: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 前

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天打算學習littlev GUI,使用Ubuntu來實現模擬,然後在安裝SDL2的時候,始終因為依賴關係導致安裝失敗,我嘗試手動去安裝那些有依賴關係的包發現根本不可行,然後我百度上也沒有找到合適的法子,但是看有的網友說是因為源的問題,我思考了下覺得這個說法有一定道理,然後我嘗試切換源,我測試了16 ...
  • 1. 檢查系統自帶的Mysql,並卸載自帶的版本 2. 卸載系統自帶的mysql及其依賴 3. 給CentOS添加rpm源,並且選擇較新的源 1)下載rpm包 2)安裝本地mysql源 3)驗證是否安裝成功 4)修改預設版本為5.7 註:如下是截取的老徐之前文章 -》原文 http://istest ...
  • HTTP/HTTPS抓包工具--Fiddler Fiddler[ˈfɪdlə(r)] 1. HTTP代理神器Fiddler Fiddler是一款強大Web調試工具,它能記錄所有客戶端和伺服器的HTTP請求。 Fiddler啟動的時候,預設IE的代理設為了127.0.0.1:8888,而其他瀏覽器是需 ...
  • 參考資料: RAID data striping spanned volume 從raid0到raid7,raid陣列各級別介紹 本文所使用的圖片來源於互聯網,若有侵權,煩請聯繫,謝謝。 簡介 RAID出現的目的是為了數據的冗餘,或者性能的提升,或者兩者兼顧。早期想實現這樣的功能,可能需要購買一些基 ...
  • 第一階段 start.S 首先我們可以在u boot.lds中看到 ,即指定了入口 ,`_start start.S`的最開始; 1. reset 在 中的 normal_start_flow: / set stack for C code / ldr x0, =(CONFIG_SYS_INIT_S ...
  • rpmbuild├── BUILD #當我們rpmbuild -ba 構建rpm時會自動在這個目錄下進行編譯├── BUILDROOT #會當成臨時根,會將編譯好的軟體包生成在這個目錄下├── RPMS #編譯好的rpm包會存放在這個文件夾├── SOURCES #放源碼包,一般為tar.gz格式├ ...
  • 1.poweroff 關閉系統(1) 2.halt 關閉系統(2) 3.reboot 重啟系統 4.pwd 查看當前所在目錄的絕對路徑 5.mkdir 文件名 創建一個目錄文件 6.rm 文件名 刪除文件(如果刪除目錄文件需要加上-r,如果強制刪除需要加上-f) 7.cat 文件名 查看文件內容(適 ...
  • Windows 2008 Server在預設情況下,是禁止使用桌面桌面連接後播放聲音的(提示音頻服務未啟用)。可以通過下麵的方法啟用音頻: 管理工具->遠程桌面服務->遠程桌面會話主機配置, 在配置界面中的“連接”項下,打開RDP-Tcp的屬性->客戶端設置選項卡中,把重定向里的“禁用以下項目”中的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...