RPATH與RUNPATH


RPATH與RUNPATH

原文鏈接: ckammRPATH and RUNPATH

DT_RPATH通常設置在這樣一種可執行程序中,它依賴的庫無法在默認位置中被找到。舉例來說,Qt Creator自帶一個Qt庫的副本,而且有一個指向庫文件所在目錄的rpath。當你構建自己的Qt庫而不將其安裝到全局位置時,這也是很有用的:qmlviewer之類的二進制文件之所以能夠工作,是因為它們包含了一個指向了編譯時所用Qt庫的rpath。

如果這些文件沒有設置rpath,在啟動它們之前你需要顯式地設置LD_LIBRARY_PATH,或寫一個替你做這些事情的腳本。由於LD_LIBRARY_PATH是一個環境變量,它也有自身的一些問題。

很不幸的是:在基於glibc的系統中,動態加載器的搜索路徑有些混亂。尤其是在RPATH和RUNPATH二者的區別上。這方面的文檔非常匱乏: Google給出的第一個結果 是不正確的,可能只是過時了。ld和ld.so的man頁面是不完整的,而且dlopen中對 RUNPATH如何起作用的描述是錯的Debain Wiki 一開始說得不錯,但是和dlopen頁面有同樣的錯誤,而且后面有些自相矛盾。

另一個混亂的來源是:根據你的發行版的不同,“ld”的-rpath參數表現出不同的行為。在一些發行版中生成DT_RPATH,而在另外一些發行版中卻同時生成DT_RPATH和DT_RUNPATH。

好的,這並不嚴重,但問題是什么呢?

簡單地說:在你的應用程序中設置DT_RUNPATH(或者DT_RUNPATH和DT_RPATH)並不足以保證它鏈接到你所指定目錄中的庫。

一個導致問題的具體例子:

  • Qt Creator鏈接到它自帶的QtGui
  • 它通過dlopen加載了系統提供的KDE插件,該插件(間接)依賴QtDBus
  • 如果Qt Creator的二進制程序設置了RPATH而沒有RUNPATH:Qt Creator自帶QtDBus被加載
  • 如果Qt Creator的二進制程序設置了RUNPATH:系統提供的QtDBus被加載且導致Qt Creator終止。

該錯誤將會類似這樣“Cannot mix incompatible Qt library (version 473) with this library (version 474)”[不能將當前庫(版本474)與不兼容的Qt庫(版本473)混用]。因為即使版本間是二進制兼容的,你也不能混用它們。QtDBus可能會依賴QtCore中已經發生變化或者在4.7.4中新增的私有API。

對於所有的鏈接到自有QtGui庫且運行在帶有KDE的系統上的應用程序,都可能發生這種問題。但是該問題也並不局限於KDE:任何使用了先前未加載的Qt庫的插件,都可能查找到錯誤的庫。

為什么會這種情況?

實驗以及對glibc源碼(elf/dl-load.c中的_dl_map_object)閱讀表明,庫的搜索順序如下:

除非正被加載的對象(object)擁有RUNPATH:
    正被加載對象的RPATH,
        然后是其加載者(loader)的RPATH(除非它有RUNPATH),...,
        直到搜索鏈的結束,它要么是可執行程序,
        要么是通過dlopen加載的對象
    除非可執行程序擁有RUNPATH:
        該可執行程序的RPATH
LD_LIBRARY_PATH
正被加載對象的RUNPATH
ld.so.cache
默認路徑


該過程解釋了這種行為:我們依賴於插件加載時檢查可執行程序的RPATH。可執行程序的RUNPATH並不被用來查找間接依賴的庫。

我們該如何做?

當你發布二進制(程序)時,要么使用RPATH且不使用RUNPATH,要么確保LD_LIBRARY_PATH在運行前被設置。當你在“ld”默認是–enable-new-dtags(因此-rpath會添加RUNPATH)的系統中構建Qt時,要明白一點:在啟動使用該版本Qt構建的程序時,你可能必須要先設置LD_LIBRARY_PATH。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM