2012-07-15 127 views
6

與版本化共享庫鏈接,我試圖通過loadLibrary調用來加載在我的Android應用程序兩個共享庫:中的Android NDK

System.loadLibrary("mywrapper"); 
System.loadLibrary("crypto"); 

我堅持跑步,捕捉`UnsatisfiedLinkError。這是一個更詳細的錯誤版本。

Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1969]: 
    130 could not load needed library 'libcrypto.so.1.0.0' for 
    'libmywrapper.so' (load_library[1111]: Library 'libcrypto.so.1.0.0' not found) 

任何想法?

花了一些時間後,我發現Android不支持版本化的庫。有沒有人面臨同樣的問題?

回答

2

似乎android有一個加載版本庫的問題。手頭的問題是因爲在我的情況下libcrypto.so.1.0.0庫所謂的名稱。即使您重命名庫並嘗試將其作爲預先編譯的共享庫加載到android make文件中,它也會失敗(它必須是因爲庫名稱以某種方式嵌入到文件中,並且任何與其鏈接的庫都期望成爲鏈接到一個同名的庫)

我希望在android中處理帶有版本名稱的庫時,還有其他方法。

現在我通過使用openssl的靜態庫並將它們與我自己的共享庫鏈接起來,從而一起迴避了這個問題。

2

2014年,仍然不支持版本化的共享庫。所以我做了一個腳本來修補SONAME。只需將腳本指向輸入所有版本庫的放置位置即可。然後檢查輸出目錄「unver」。

#!/bin/bash 

DIR="$1" 

if [ "$DIR" == "" ]; then 
    echo "Usage: fix-soname.sh <target dir>" 
    exit 
fi 

if [ ! -d $DIR ]; then 
    echo "Not found: $DIR" 
    exit 
fi 

OUT="$DIR/unver" 
echo "Input=$DIR" 
echo "Output=$OUT" 

CWD=$(pwd) 
cd $DIR 

# prep dirs 
mkdir -p $OUT 
rm -f -R $OUT/* 

# rename libs and copy to out dir 
find "$DIR" -type f -name '*.so*' | while read FILE; do 

    NAME=$(basename "$FILE") 
    SONAME=$NAME 

    while read SYMLINK; do 
     X=$(basename "$SYMLINK") 
     #echo "$X (${#X}) -> $NAME (${#NAME})" 
     if [ "${#X}" -lt "${#SONAME}" ]; then 
      SONAME=$X 
     fi 
done<<EOT 
`find -L $DIR -samefile $FILE` 
EOT 

    #echo $SONAME 
    cp -f $SONAME $OUT/ 
done 

# patch libs in out dir 
find "$OUT" -type f -name '*.so*' | while read FILE; do 

    # get file name without path 
    NAME=$(basename "$FILE") 

    # extract SONAME from shared lib 
    SONAME=`readelf -d $FILE | grep '(SONAME)' | grep -P '(?<=\[)(lib.*?)(?=\])' -o` 

    #echo "$NAME [$SONAME]" 

    # patch SONAME if required 
    if [ "$NAME" != "$SONAME" ]; then 
     L1=${#NAME} 
     L2=${#SONAME} 
     LDIFF=$((L2-L1)) 
     #echo "$NAME [$SONAME] ($LDIFF)" 

     if [ "$LDIFF" -gt "0" ]; then 
      SONEW=$NAME 
      for ((c=1; c<=$LDIFF; c++)); do 
       SONEW+="\x00" 
      done 
      echo "$NAME [$SONAME] -> $SONEW ($LDIFF)" 
      rpl -R -e "$SONAME" "$SONEW" $OUT 
     fi 
    fi 
done 

cd $CWD 
+0

它沒有爲我工作... 我在openssl源代碼目錄上運行它,並且編譯了二進制文件,'unver'目錄輸出與原始二進制文件完全相同libcrypto.so – Giovani 2015-02-13 11:48:56

+0

您可以在腳本中取消註釋#echo並查看出現問題的地方。 – sviborg 2015-02-14 12:43:16

+0

或者使用[patchelf](https://www.mankier.com/1/patchelf)來修復它。 – 2017-10-29 10:11:58

4

我在爲Android構建libwebsockets時遇到了同樣的問題,它需要與OpenSSL鏈接。我以libssl.so爲例。你應該爲相關的.so文件做同樣的事情。

Before: 
 
[email protected]:~$ objdump -p libssl.so | grep so 
 
libssl.so:  file format elf32-little 
 
    NEEDED    libcrypto.so.1.0.0 
 
    NEEDED    libdl.so 
 
    NEEDED    libc.so 
 
    SONAME    libssl.so.1.0.0 
 

 
After 
 
[email protected]:~$ rpl -R -e .so.1.0.0 "_1_0_0.so" libssl.so 
 
Replacing ".so.1.0.0" with "_1_0_0.so" (case sensitive) (partial words matched) 
 
. 
 
A Total of 2 matches replaced in 1 file searched. 
 
[email protected]:~$ objdump -p libssl.so | grep so 
 
libssl.so:  file format elf32-little 
 
    NEEDED    libcrypto_1_0_0.so 
 
    NEEDED    libdl.so 
 
    NEEDED    libc.so 
 
    SONAME    libssl_1_0_0.so 
 

 
And don't forget to change file name "libssl.so" to "libssl_1_0_0.so".

的黑客作品。我已經運行Android應用程序來證明它。看到我的咆哮在http://computervisionandjava.blogspot.com/2015/05/trouble-with-versioned-shared-libraries.html

+0

我無法使rpl與.so文件一起工作,但我只能用VIM編輯文件,並在那裏替換字符串。很棒的黑客。謝謝! – Xample 2017-02-08 14:57:50