簡體   English   中英

Makefile混亂中的鏈接器庫路徑

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM