編譯時連結boost庫的困惑
對於一個客戶,我需要在系統中添加 boost 1.54。所以我下載了最新版本(1.55)並將其建構在一個特殊的目錄中:/usr/local/lib/boost1.55/。這行得通。然後我不得不以這種方式調整 Makefile。
LIBS = $(SUBLIBS) -L/usr/lib/x86_64-linux-gnu -LC:/deps/miniupnpc -lminiupnpc -lqrencode -lrt -LC:/deps/boost/stage/lib -Lc:/deps/db/ build_unix -Lc:/deps/ssl -LC:/deps/libqrencode/.libs -lssl -lcrypto -ldb_cxx -L/usr/local/lib/boost1.55/boost_system-mgw46-mt-sd-1_54 -L/usr /local/lib/boost1.55/boost_filesystem-mgw46-mt-sd-1_54 -L/usr/local/lib/boost1.55/boost_program_options-mgw46-mt-sd-1_54 -L/usr/local/lib/boost1 .55/boost_thread-mgw46-mt-sd-1_54 -lQtDBus -lQtGui -lQtCore -lpthread -lboost_system -lboost_filesystem -lboost_program_options -lboost_thread
在未修改的 Makefile 中,boost 連結如下所示:
-lboost_thread-mgw46-mt-sd-1_54
但這沒有用。我無法編譯它,因為它沒有找到。所以我添加了(如您在上面看到的)
-L/usr/local/lib/boost1.55/boost_thread-mgw46-mt-sd-1_54
和
-lboost_thread
否則它也不會編譯。編譯成功後,我在二進製文件上執行了 ldd ,它顯示:
libboost_system.so.1.53.0 => /usr/lib/x86_64-linux-gnu/libboost_system.so.1.53.0 (0x00007f416c169000) libboost_filesystem.so.1.53.0 => /usr/lib/x86_64-linux-gnu/ libboost_filesystem.so.1.53.0 (0x00007f416bf52000) libboost_program_options.so.1.53.0 => /usr/lib/x86_64-linux-gnu/libboost_program_options.so.1.53.0 (0x00007f416bce4000) libboost_thread.so.1.53.0 => / usr/lib/x86_64-linux-gnu/libboost_thread.so.1.53.0 (0x00007f416bace000)
1.53 是包管理器安裝的版本。我不明白為什麼它連結到這個版本。如果我沒有安裝 1.55,它就不會編譯,但現在它沒有連結到這個版本。對此有何解釋?
實際上我的目標是不使用動態連結庫,我還沒有想出如何做到這一點,但我仍然想知道為什麼上面沒有按預期工作。
您沒有說這是 Linux 的哪個發行版,但通常有一個目錄,您可以在其中添加動態可連結庫。在 Fedora 等 Redhat 發行版上,此目錄位於此處,
/etc/ld.so.conf.d/
.LD
您可以使用新安裝的庫的路徑將文件添加到此目錄,如下所示:
$ cat /etc/ld.so.conf.d/myboost.conf /usr/local/lib/boost1.55
然後執行這個命令:
$ ldconfig -v
這將處理所有庫並重建“記憶體”,
/etc/ld.so.cache
. 此記憶體用於在指定庫時定位庫,如下所示:-lboost_thread-mgw46-mt-sd-1_54
.範例輸出
$ ldconfig -v /usr/lib64/atlas: libclapack.so.3 -> libclapack.so.3.0 libptcblas.so.3 -> libptcblas.so.3.0 libf77blas.so.3 -> libf77blas.so.3.0 libcblas.so.3 -> libcblas.so.3.0 liblapack.so.3 -> liblapack.so.3.0 libptf77blas.so.3 -> libptf77blas.so.3.0 libatlas.so.3 -> libatlas.so.3.0 /usr/lib64/wxSmithContribItems: libwxflatnotebook.so.0 -> libwxflatnotebook.so.0.0.1 ...
在為設置添加路徑時,我喜歡通過此輸出進行確認,以確保事情按照我期望的方式進行。
LD的記憶體
您也可以隨時使用以下命令列印 .cache 文件的內容:
$ ldconfig -p | head -10 2957 libs found in cache `/etc/ld.so.cache' lib3ds-1.so.3 (libc6,x86-64) => /usr/lib64/lib3ds-1.so.3 libzvbi.so.0 (libc6,x86-64) => /usr/lib64/libzvbi.so.0 libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib64/libzvbi-chains.so.0 libzrtpcpp-1.4.so.0 (libc6,x86-64) => /usr/lib64/libzrtpcpp-1.4.so.0 libzmq.so.1 (libc6,x86-64) => /usr/lib64/libzmq.so.1 libzmq.so (libc6,x86-64) => /usr/lib64/libzmq.so libzipios.so.0 (libc6,x86-64) => /usr/lib64/libzipios.so.0 libzipios.so (libc6,x86-64) => /usr/lib64/libzipios.so libzip.so.1 (libc6,x86-64) => /usr/lib64/libzip.so.1
為什麼我的 ldd 輸出仍然使用 1.53?
這是因為您的二進製文件正在使用動態庫。所以當二進製文件被編譯時,它是針對 1.55 版本的庫。但是,當您使用 查詢二進製文件時
ldd
,它位於使用.cache
文件內容的環境中。因此,與此二進製文件使用的符號相關聯的記憶體中的庫與 1.53 的庫匹配,因此您會看到這些庫。您的環境對 1.55 庫一無所知,只有您的建構環境,即您的 Makefile,知道這一點。
動態庫
將這些中的功能視為符號。符號是一個名稱,因此這些名稱通常不會從一個庫版本更改為另一個版本。因此,如果您要查看諸如 boost 之類的庫,您可以使用該工具
readelf
獲取其中一個.so
文件中的符號列表。例子
$ readelf -Ws /usr/lib64/libboost_date_time-mt.so | head -10 Symbol table '.dynsym' contains 261 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 000000335aa096a8 0 SECTION LOCAL DEFAULT 9 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8bad_castD2Ev@GLIBCXX_3.4 (2) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt6locale5_ImplD1Ev@GLIBCXX_3.4 (2) 4: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _ZTINSt6locale5facetE@GLIBCXX_3.4 (2) 5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND wcslen@GLIBC_2.2.5 (3) 6: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _ZTISt11logic_error@GLIBCXX_3.4 (2)
在上面的輸出中,您可以看到一些
FUNC
定義,這些是用於將執行檔中的函式與某個.so
庫中的函式“連結”的名稱。我過度簡化了這一點,並且可能稍微解釋了一些事情,但我只是想讓您大致了解引擎蓋下的機器如何工作的機制。
參考