[英]Linker library path in makefile confusion
我已經編程了一段時間,但我仍然不完全了解鏈接器的行為。
例如,今天我下載並安裝了要在Linux中的應用程序中使用的庫。 (它是Xerces-用於解析XML文件)。
我創建了一個makefile,並在命令:-L / usr / local / lib中提供了指向.so和.a文件的路徑,並告訴它要包含的庫名稱:-lxerces-c-3.1。
我的應用程序編譯良好,但在運行時失敗,並顯示“無法打開共享庫文件libxerces-c-3.1.so”。 當我在makefile中正確給它提供路徑和名稱時,為什么會這樣呢?
然后,我將庫路徑添加到.bashrc文件中的LD_LIBRARY_PATH變量中,然后它起作用了。 很好,但是如果我現在在我的makefile中刪除該庫的路徑,甚至不包含該庫的名稱,它仍然可以工作。
我對這里發生的事情感到困惑。 僅通過將路徑分配給LD_LIBRARY_PATH變量,它如何仍能找到正確的庫,並且僅在我這樣做時才有效? 我在其他地方讀過甚至沒有使用LD_LIBRARY_PATH。
我對此表示感謝。 這個問題有點長,希望不會成為題外話,但我希望其他人也可以從中學習。 謝謝
編譯和運行是不同的事情。 :)
1)生成文件包含有關如何構建應用程序的規則。 因此,當您編寫如下規則時:
-L/usr/local/lib -lxerces-c-3.1
您正在將選項傳遞給鏈接器。 -L
選項告訴鏈接器將其他庫(在本例中為“ / usr / local / lib”)添加到鏈接器的搜索路徑。 -l
選項為應該鏈接的庫命名。
2)當您運行可執行文件時,加載器需要找到所有必需的庫。 例如,在Linux系統上,您可以使用ldd命令查看使用了哪些共享庫。 例如在我的系統上:
ldd FEParser
linux-vdso.so.1 => (0x00007ffcdc7c9000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f835b143000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f835ae3d000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f835ac27000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f835a862000)
/lib64/ld-linux-x86-64.so.2 (0x00007f835b447000)
由此,您可以看到鏈接到'=>'標記左側的庫的名稱以及右側的庫路徑。 如果未找到庫,它將顯示為丟失。
現在,根據您的情況,由於提供了要使用的路徑和庫名稱,因此您能夠成功編譯並鏈接程序。 由於加載程序無法在運行時找到庫,因此無法運行程序。
您在這里有幾種選擇:
1)您可以將庫移動到裝載程序搜索路徑中的目錄中。
2)您可以修改LD_LIBRARY_PATH
,從而將其他目錄添加到裝載程序搜索路徑。 此外,在LD_LIBRARY_PATH
指定的目錄將傳遞到鏈接器(它將附加在所有-L
標志之后)。 您確實需要注意這一點,就像您對其進行了全局設置(例如.bashrc
)一樣,它將影響您所做的所有編譯。 您可能會或可能不會想要此行為。
3)正如其他人所指定的,您可以使用-Wl,rpath=....
,但已棄用,並且我很少使用它。
4)如果需要將庫安裝在不尋常的位置,則可以在/etc/ld.so.conf.d
下添加一個創建文件,該文件包含例如(文件為yaml.conf):
# yaml default configuration
/opt/yaml/lib
在系統啟動時,加載程序讀取該目錄中的所有文件,並將路徑附加到加載程序路徑。 如果您對此目錄進行了修改,則可以使用ldconfig
命令使加載程序重新處理/etc/ld.so.con.d
。 注意:我知道這適用於centOS和GNU / Linux的Ubuntu版本-不能權威地談論其他版本。
使用-Wl,-rpath=/usr/local/lib
編譯程序。 這樣,您將/ usr / local / lib添加到程序的運行時庫搜索補丁中,並且不需要LD_LIBRARY_PATH
警告 :由於現代動態鏈接器認為rpath
已棄用,因此您還可以通過指定runpath
-Wl,-rpath=/usr/local/lib,--enable-new-dtags
來設置runpath
(取代它)
這里沒有謎。 鏈接器(調用該文件以生成可執行文件,例如ld
)和運行時鏈接器(負責在執行程序時加載共享庫的一個,例如ld.so
)的默認庫路徑是不同的。 運行時鏈接程序使用LD_LIBRARY_PATH,而鏈接程序使用構建ld時配置的內容。
在您的情況下, /usr/local/lib
似乎是其中一部分,而不是另一部分。
如果您使用的是靜態鏈接,則只需告訴鏈接器在編譯/鏈接時庫在哪里。 該庫(或必要時,盡可能多的庫)被復制到可執行文件中,並且可執行文件是獨立的。
但是由於種種原因,如今,我們通常使用動態鏈接,而不是靜態鏈接。 使用動態鏈接,您必須告訴鏈接器在編譯/鏈接時在哪里可以找到庫, 而動態鏈接器( ld.so
)必須能夠在運行時找到該庫。
如果該庫位於標准位置之一( /lib
, /usr/lib
等)中,則沒有問題。 但是,如果通常在非標准位置鏈接到庫,則必須將該非標准位置添加到LD_LIBRARY_PATH中,以便運行時鏈接程序始終能夠找到它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.