我正在嘗試編譯一個程式prog
並將其連結到 OpenSSL 的 1.0.2 beta,從原始碼建置並安裝在/usr/local/ssl-1.0.2
.在使用 0.9.8 的舊系統上,這可以順利完成。在安裝了 1.0.1 的較新的系統上,這需要更多的工作。我想知道為什麼。
1) 在 Ubuntu 10.04 上,使用 OpenSSL 0.9.8:
以下是我針對 1.0.2 進行編譯和連結的步驟。
$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto
=> 僅顯示 0.9.8 文件,因此我添加了 1.0.2 文件的路徑...
$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto
=>
libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
libcrypto.so.0.9.8 (libc6, hwcap: 0x0008000000008000) => /lib/i686/cmov/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6, hwcap: 0x0004000000000000) => /lib/i586/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6, hwcap: 0x0002000000000000) => /lib/i486/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6) => /lib/libcrypto.so.0.9.8
libcrypto.so.0.9.8 (libc6) => /usr/lib/libcrypto.so.0.9.8
libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so
這樣我就可以編譯prog
...
$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog
=>
libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0x0083b000)
...並且它與 1.0.2 正確連結。
2) 在 Debian Wheezy 上,使用 OpenSSL 1.0.1:
同樣的步驟,不同的結果。
$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto
=>
libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
同樣,我添加了 1.0.2 的路徑...
$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto
=>
libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so
然後我嘗試編譯...
$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog
=>
libcrypto.so.1.0.0 => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 (0xb7591000)
但這裡它與 1.0.2 沒有連結。編譯時庫路徑是正確的(用 , 指定-L
,gcc
否則會失敗,因為 中使用的某些函數prog
特定於 1.0.2),但運行時庫路徑則不然。
3) 如何讓它在 Wheezy 上運行
有或沒有跑步ldconfig /usr/local/ssl-1.0.2/lib
:
$ gcc -o prog ... -Wl,--rpath=/usr/local/ssl-1.0.2/lib -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog
=>
libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0xb7592000)
或者,export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib
在運行之前運行gcc
。
我想知道什麼
按照 mr.spuratic 的建議使用LD_DEBUG=libs ./prog
,我發現在 中找到了路徑/etc/ld.so.cache
。我打開該文件,發現 .so 的查找順序與 .so 的輸出相對應ldconfig -p
。
所以實際的問題是:
- 為什麼 1.0.2 檔案在 1) 中位於 ldconfig 清單的頂部,但在 2) 中卻沒有?純粹的隨機性?由於 1.0.1 和 1.0.2 檔案具有相同後綴而造成混淆? (“1.0.0”)
或者,換句話說,
- 為什麼 3) 中新增的標誌在 1) 中不需要?
答案1
針對非預設套件進行編譯/連結時需要注意三件事:
- 標頭(通常
CFLAGS
) - 編譯時庫路徑(通常
LDFLAGS
) - 運行時庫路徑(路徑通過
LDFLAGS
,LD_RUN_PATH
,LD_LIBRARY_PATH
或ld.so.conf
)
你還沒有說prog
是什麼,所以我不知道它的配置可能有多好(或者如果它使用autoconf?),我見過很多只可靠地執行前兩個步驟。
CFLAGS
在連結階段,庫路徑順序是相關的,假設您使用的是 GNU 工具鏈(gcc 和 binutils),您可能可以透過先前的設定configure
(或直接設定Makefile
)來了解發生了什麼:
export CFLAGS="-Wl,-t"
這會將-t
追蹤選項傳遞給連結器。如果在 make 過程中只得到簡潔的「CC」和「LD」行輸出,則可能需要在 make 指令中新增V=1
或。VERBOSE=1
在運行時,您可以ld.so
透過仔細設定來查看嘗試的內容LD_DEBUG
,例如
LD_DEBUG=libs ./myprog
files
(或嘗試或的值symbols
以獲取更多詳細資訊)
要在建置時正確指定所有三個參數,您應該能夠執行以下操作:
export CFLAGS="-I/usr/local/ssl-1.0.2/include"
export LDFLAGS="-L/usr/local/ssl-1.0.2/lib -R/usr/local/ssl-1.0.2/lib"
然後重新配置/重新編譯。
您使用的是--openssldir
而不是更傳統的--prefix
(我推薦後者,並且make install_sw
如果您不需要默認安裝為您提供的 1000 個左右的手冊頁和符號鏈接,也可以使用)。這可能是問題的一部分。由於某種原因,您顯示的 .so 庫已知沒有ld.so
版本後綴(例如.so.1.0.2
),正確的“ make install
”應該為您設定它(透過link-shared
main 中的目標Makefile
)。
此-R
選項指示連結器在特定 OpenSSL 函式庫的可執行輸出中嵌入 RPATH,以便它不需要依賴執行時間連結器 ( ld.so
) 通常提供的預設值。您可以使用以下命令修改現有的二進位文件chrpath
反而。
這或多或少相當於導出LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib
。您可以在此處閱讀有關 RPATH 和相關 RUNPATH 的更多資訊:http://blog.tremily.us/posts/rpath/
作為最後的手段,您可以建立不帶「共享」或「不共享」的OpenSSL,這將為您提供不會出現此問題的靜態庫(但很可能會出現其他問題,例如在ELF .so 中使用,導致PIC /PIE問題)
根據更新的詳細信息,我認為問題在於 1.0.1 和 1.0.2beta 都將 .so 版本後綴(SONAME)設為 1.0.0。在第一個只有 0.9.8 的系統上,這不會造成任何問題;第二個版本為 1.0.1 和 1.0.2 的版本均為 1.0.0,根據順序,這是「首場比賽獲勝」ld.so.{conf,d}
。請記住,ld
編譯時連結器是與執行時間連結器不同的程序ld.so
,並且可以具有不同的行為(通常會導致符號錯誤或更糟,如您所見)。
$ cd /usr/local/src/openssl/openssl/1.0.2beta1
$ readelf -a libssl.so | grep SONAME
0x0000000e (SONAME) Library soname: [libssl.so.1.0.0]
$ cat verchk.c
int main(int argc, char *argv[]) {
printf("build: %s\n",OPENSSL_VERSION_TEXT);
printf("run : %s\n",SSLeay_version(SSLEAY_VERSION));
return 0;
}
$ gcc -Wall -I/usr/local/src/openssl/openssl-1.0.2-beta1/include \
-Wl,-rpath /usr/local/src/openssl/openssl-1.0.2-beta1/ \
-o verchk /usr/local/src/openssl/openssl-1.0.2-beta1/libcrypto.so verchk.c
$ ./verchk
build: OpenSSL 1.0.2-beta1 24 Feb 2014
run : OpenSSL 1.0.2-beta1 24 Feb 2014
$ grep SHLIB_M...R= Makefile
SHLIB_MAJOR=1
SHLIB_MINOR=0.0
更新
OpenSSL-1.1 進行了一些 API 層級更改,上述程式碼將無法使用 v1.1 標頭和較舊的程式庫進行編譯 ( undefined reference to `OpenSSL_version'
)。
SSLeay_version()
現已棄用,並且(取決於OPENSSL_API_COMPAT
)可能會被#define
-d 為正確的 API 函數OpenSSL_version()
。
答案2
新庫的路徑是否位於其中的文件之一/etc/ld.so.conf.d
?下次運行:-
#ldconfig -v
重建緩存。如果你動作很快,你應該會在列印出來的長列表中看到新的庫(或透過管道將其傳遞到grep
or less
)
也許該路徑已經在第一台伺服器中,但不在第二台伺服器中?