Compiling

使用 make 編譯:連結到庫

  • February 15, 2018

我正在使用 make 為應用程序編譯 PHP。問題是當我做一個 ldd php 我有這樣的事情:

libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007f5b4e661000)

但是 libk5crypto.so.3 是指向 libk5crypto.so.3.1 的符號

我希望我的 php 直接指向 libk5crypto.so.3.1。

是否可以 ?

編輯:我有一個帶有我自己編譯的 php 伺服器的 web 應用程序。我不想將它安裝在 /etc 中,我只想讓它在我的應用程序中。

在我的應用程序中,我有一個名為 server 的文件夾,用於儲存 php、fop、mapserver 等…

在我的 php 文件夾中,我有一個 lib 文件夾,裡面放了所有依賴項(ldd bin/php)

當我安裝我的應用程序時,我修改文件 /etc/ld.so.conf 以從我的 php 伺服器添加 lib 目錄,然後我執行 ldconfig。

有時這些庫已經存在於 /usr/lib/x86_64-linux-gnu 中,而 PHP 會使用這個庫而不是他文件夾中的庫。這幾乎不是問題,但有時我在 /usr/lib… 中有一個 lib,它具有相同的主要版本,但次要版本較低。PHP 嘗試從 /usr/lib 獲取它並拋出一個錯誤,因為 php 與最新的依賴項一起編譯。

正因為如此,我想直接指向 libk5crypto.so.3.1。

當我更新我的應用程序時,我刪除了我的 php,並添加了一個包含所有新庫的新庫。

另一件事,我試圖告訴 PHP 在給定目錄中查看庫,但我的問題是我不知道編譯時它會在哪裡。

JigglyNaga 的編輯:我編譯 PHP,然後編譯 imap 和其他擴展。問題在於 php 和擴展。所以 imap 的編譯時間較短,所以我給你所有。

root@ubuntu16:~/compilPHP/php-7.2.2/ext/imap# make
/bin/bash /root/compilPHP/php-7.2.2/ext/imap/libtool --mode=compile cc  -I. -I/root/compilPHP/php-7.2.2/ext/imap -DPHP_ATOM_INC -I/root/compilPHP/php-7.2.2/ext/imap/include -I/root/compilPHP/php-7.2.2/ext/imap/main -I/root/compilPHP/php-7.2.2/ext/imap -I/php/include/php -I/php/include/php/main -I/php/include/php/TSRM -I/php/include/php/Zend -I/php/include/php/ext -I/php/include/php/ext/date/lib -I/usr/include/c-client  -DHAVE_CONFIG_H  -g -O2   -c /root/compilPHP/php-7.2.2/ext/imap/php_imap.c -o php_imap.lo
mkdir .libs
cc -I. -I/root/compilPHP/php-7.2.2/ext/imap -DPHP_ATOM_INC -I/root/compilPHP/php-7.2.2/ext/imap/include -I/root/compilPHP/php-7.2.2/ext/imap/main -I/root/compilPHP/php-7.2.2/ext/imap -I/php/include/php -I/php/include/php/main -I/php/include/php/TSRM -I/php/include/php/Zend -I/php/include/php/ext -I/php/include/php/ext/date/lib -I/usr/include/c-client -DHAVE_CONFIG_H -g -O2 -c /root/compilPHP/php-7.2.2/ext/imap/php_imap.c  -fPIC -DPIC -o .libs/php_imap.o
/bin/bash /root/compilPHP/php-7.2.2/ext/imap/libtool --mode=link cc -DPHP_ATOM_INC -I/root/compilPHP/php-7.2.2/ext/imap/include -I/root/compilPHP/php-7.2.2/ext/imap/main -I/root/compilPHP/php-7.2.2/ext/imap -I/php/include/php -I/php/include/php/main -I/php/include/php/TSRM -I/php/include/php/Zend -I/php/include/php/ext -I/php/include/php/ext/date/lib -I/usr/include/c-client  -DHAVE_CONFIG_H  -g -O2   -o imap.la -export-dynamic -avoid-version -prefer-pic -module -rpath /root/compilPHP/php-7.2.2/ext/imap/modules  php_imap.lo -Wl,-rpath,/usr/lib/x86_64-linux-gnu/mit-krb5 -L/usr/lib/x86_64-linux-gnu/mit-krb5 -lc-client -lcrypt -lpam -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lssl -lcrypto
cc -shared  .libs/php_imap.o  -L/usr/lib/x86_64-linux-gnu/mit-krb5 -lc-client -lcrypt -lpam -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lssl -lcrypto  -Wl,-rpath -Wl,/usr/lib/x86_64-linux-gnu/mit-krb5 -Wl,-soname -Wl,imap.so -o .libs/imap.so
creating imap.la
(cd .libs && rm -f imap.la && ln -s ../imap.la imap.la)
/bin/bash /root/compilPHP/php-7.2.2/ext/imap/libtool --mode=install cp ./imap.la /root/compilPHP/php-7.2.2/ext/imap/modules
cp ./.libs/imap.so /root/compilPHP/php-7.2.2/ext/imap/modules/imap.so
cp ./.libs/imap.lai /root/compilPHP/php-7.2.2/ext/imap/modules/imap.la
PATH="$PATH:/sbin" ldconfig -n /root/compilPHP/php-7.2.2/ext/imap/modules

最終編輯:它起作用了,我在製作之前更改了 rpath。export LDFLAGS=’-Wl,-rpath, $ ${ORIGIN}/../lib’ 非常感謝您的所有回答。

將此添加為另一個答案,因為另一個答案仍然可以獨立存在,但是您的問題(在您澄清之後)是不同的。如果這是與您的應用程序以及系統附帶的庫有關,那麼這種情況是不可比較的。您幾乎已經完成了修復它需要做的事情,但還不夠:-)

您的問題有幾種解決方案:LD_LIBRARY_PATH、、rpath運送更改的庫和多次編譯。每個都有其優點和問題,所以讓我解釋一下:

  • LD_LIBRARY_PATH

如果你走這條路,那麼你在執行程序之前設置一個環境變數。它可能需要您在二進製文件周圍使用包裝腳本(即,您執行一個首先設置然後執行/path/to/my/php的 shell 腳本,而不是直接執行)。LD_LIBRARY_PATH``/path/to/my/php

這種方法的缺點是它有點脆弱:

  • LD_LIBRARY_PATH附加到庫搜尋路徑中,但不會替換它。這意味著如果有問題的庫是在系統範圍內安裝的,但由於某種原因無法載入您提供的庫,則動態連結器將退回到系統提供的庫。
  • 呼叫 shell 腳本的要求意味著您有一個額外的 fork/exec 呼叫,這可能會使事情出錯。這可以通過exec在你的 shell 腳本中使用命令來緩解(這樣腳本就會被 php 二進製文件替換,並且你的 php 程序是父程序的正確子程序),但它仍然很混亂另一方面,它允許您在儲存庫的位置方面具有一定的靈活性(即,如果系統提供的庫在某些情況下足夠好,則可以將其從LD_LIBRARY_PATH目錄中刪除)
  • rpath

在這裡,想法是你告訴編譯器(通過gcc -Wl,-rpath,'/path/to/library')確切地在哪裡尋找庫。這在編譯時被硬編碼到程序中,然後動態連結器將絕對忽略您提供的庫之外的rpath版本,包括系統提供的版本。這避免了LD_LIBRARY_PATH上面的混亂,但缺點是這會使事情變得不那麼靈活;如果您需要在文件系統中移動內容,則需要重新編譯所有內容。

這也意味著,如果您的使用者希望看到以不同方式安裝的東西,那他們就太倒霉了。他們可能不喜歡那樣。

這兩種方法都記錄在ld.so手冊頁中。

  • 運送更改的庫

在這裡,想法是不要嘗試連結到libk5crypto.so.3,而是連結到libmycorp-k5crypto.so.3。在這種情況下,動態連結器獲取系統提供的可能性為零libk5crypto.so.3。這裡的優點是安裝後相當簡單和優雅;不利的一面是人們可能會開始懷疑您是否libk5crypto進行了更改(並要求您提供更新檔),並且您還必須深入研究libk5crypto.so建構系統以使其真正發出libmycorp-k5crypto.so庫。從長遠來看,它也可能看起來很糟糕,所以在你走這條路之前要小心。

  • 多次編譯

可以只在每個受支持的發行版上編譯您的應用程序,並為每個發行版發行一個包,而不是運送您的庫,而不是運送同樣在系統範圍內提供的庫。像packagecloud.io這樣的東西讓這更容易做到。由於系統上只有一個具有給定名稱的庫,因此只有一個庫可供選擇,並且沒有機會選擇錯誤的庫。缺點是你有更多的東西要測試,所以你在發佈時有更多的工作(你最好有一個好的測試套件)。

優點是,這種方法可以確保您的出貨量比其他方式少(因此您需要支持的東西更少),並且您可以告訴正在使用libk5crypto.so您不再支持的舊版本的發行版的使用者,他們應該先更新一下。

我不確定這是否可能,但不應該;這是一個非常糟糕的主意。

SONAME(libfoo.so.X 事物)在庫中定義。您可能認為完整路徑在您的 php 二進製文件中,但事實並非如此;只有 SONAME 是。這就是ldd輸出顯示libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3在輸出中的原因:名稱libk5crypto.so.3在此系統上,解析為該/usr/lib/x86_64-linux-gnu目錄下的文件。

libk5crypto.so.3不能保證始終在該位置找到該文件。路徑中的x86_64-linux-gnu部分是您正在執行 Debian 或其衍生產品之一的致命贈品;其他僅支持 biarch 而不是完整的 multiarch 的發行版,如 Red Hat,使用/usr/lib64代替。這取決於執行時動態連結器,您可以通過 調試它,通過使用它的配置(通常)ldd找出您的位置。libk5crypto.so.3``/etc/ld.so.conf

SONAME具有非常特殊的語義。如果您對完整的技術細節感興趣,我可以衷心推薦 Ulrich Drepper 關於該主題的出色文件;但如果沒有,您應該了解.so.3文件名的部分編碼 API 的兼容部分。這個想法是,當您libk5crypto出於某種原因進行更新時,系統會安裝庫,例如libk5crypto.so.3.2,移動符號連結,最後刪除舊庫。這意味著,只要庫保持ABI 兼容,任何針對它編譯的程序都不需要僅僅因為您更新了庫而重新編譯。

但是,如果您將庫的全名編碼到二進製文件中,則該優勢將完全消失,因此您必須在每次升級庫時重新編譯。你幾乎肯定不想那樣。

說了這麼多,這個問題似乎是一個XY問題。你想要達到的究竟是什麼?

引用自:https://unix.stackexchange.com/questions/423608