我的代码在
System.loadLibrary("hypoboleus");
上崩溃,并出现找不到入口点的错误。我创建了一个 so
文件并将其作为 app/src/main/jniLibs/arm64-v8a/
包含在 libhypoboleus.so
文件夹中。 Java 运行时正在调用 java.lang.Runtime.loadLibrary0
,它试图从我的 getThreadLocalsEv
文件运行 so
。
编辑:在本问题末尾添加示例代码。
这曾经在 NDK 的早期版本中工作,但我升级了,然后它让我更改了我的构建脚本。我当前的 NDK 版本是
25.2.9519653
。
具体消息文字为
java.lang.UnsatisfiedLinkError: dlopen failed: TLS symbol "_ZZN8gwp_asan15getThreadLocalsEvE6Locals" in dlopened "/data/app/~~nqWwoXRjQhq9nhyacG54hA==/hk.jennyemily.hypoboleus-EFD9ul4kulUwExi3Ee0LJQ==/base.apk!/lib/arm64-v8a/libhypoboleus.so" referenced from "/data/app/~~nqWwoXRjQhq9nhyacG54hA==/hk.jennyemily.hypoboleus-EFD9ul4kulUwExi3Ee0LJQ==/base.apk!/lib/arm64-v8a/libhypoboleus.so" using IE access model
。
入口点存在于
so
文件中: nm -D
给出 0000000000000000 W _ZZN8gwp_asan15getThreadLocalsEvE6Locals
。
我的构建线是 path-to-ndk
/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -target aarch64-linux-android-clang -nostartfiles -shared
path/hypoboleus_wrap.c
path/libhypoboleus_c.a -lm -lz -o
path/libhypoboleus.so -I
path -fPIC
[我已经简化了路径]
我已经尝试了我认为显而易见的方法,但似乎没有任何效果。我能想到的就是我正在构建 C,但错误指的是在我看来像是 C++ 条目的内容。代码主要是用 Rust(假装是 C)编写的,并带有 SWIG 生成的标准垫片。
任何人都可以告诉我,或者至少给我一些如何进一步调查的想法吗?
如果我删除标记为“删除我”的两行,那么一切都会正常。请注意,
new_engine()
没有在任何地方被调用。
use std::sync::{Arc, Mutex};
pub struct UserHandle {
ptr: Arc<Mutex<UserData>>, // delete me
}
pub struct UserData {}
#[no_mangle]
pub unsafe extern "C" fn new_engine() -> *mut UserHandle {
Box::into_raw(Box::new(UserHandle {
ptr: (Arc::new(Mutex::new(UserData {}))), // delete me
}))
}
#[no_mangle]
pub unsafe extern "C" fn get_answer() -> std::ffi::c_int { 57 }
[package]
name = "exper2"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
崩溃发生在
System.loadLibrary("exper2");
,因此它永远无法调用 get_answer()
。
package com.example.experiment1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import exper2.*;
public class MainActivity extends AppCompatActivity {
private final static String TAG = "exper2";
static {
try {
Log.d(TAG, "loading library [Java]...");
System.loadLibrary("exper2");
Log.d(TAG, "loaded library [Java].");
} catch (Exception e) {
Log.e(TAG, "exception in load library [Java]: " + e);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "looking for answer [Java]...");
int answer = exper2.get_answer();
Log.d(TAG, "answer is " + answer + " [Java]...");
TextView textView = (TextView) findViewById(R.id.answerText);
textView.setText("The answer is " + answer);
}
}
%module exper2
%{
#include "cbindgen/exper2.h"
%}
%include "cbindgen/exper2.h"
构建动态库后,您可以使用 Android studio 构建 Java,然后运行它。
LIBID=$1
GITDIR="$HOME/git"
export ARCH=aarch64-linux-android
case $LIBID in
exper2)
RUSTID=exper2
REPO=hypoboleus
ANDAPP=Experiment1
;;
*)
echo "parameter missing or unknown \"'$LIBID'\", valid hypoboleus or exper2"
exit 1
;;
esac
RUSTID2=${RUSTID//-/_}
TARGETBASE=$GITDIR/$REPO/$RUSTID/target
TARGETDIR=$TARGETBASE/$ARCH/release
export BASE2=$GITDIR/$REPO/$RUSTID
export APPBASE=$GITDIR/$REPO/$ANDAPP
export APPMAIN=$APPBASE/app/src/main
export ANDROID_HOME=/work/android/sdk
export NDK_VERSION=25.2.9519653
export API=33
export NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
export TOOLCHAIN=$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64
export CC=$TOOLCHAIN/bin/clang
export AR=$TOOLCHAIN/bin/llvm-ar
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
cd $BASE2
echo 'base for rust' $BASE2 ', target dir for rust build' $TARGETDIR
# rm -rf $TARGETBASE
mkdir -p $TARGETDIR
RUSTEX_ANDR=$TARGETDIR/lib${RUSTID2}.a
# rm -f $RUSTEX_ANDR
cargo build --target $ARCH --target-dir $TARGETBASE --release --lib
echo 'archive to' $RUSTEX_ANDR
if [[ ! -f $RUSTEX_ANDR ]]; then
echo "no library file" $RUSTEX_ANDR
ls $TARGETDIR/lib*
exit 1
fi
CBINDGEN_DIR=$BASE2/cbindgen/
rm -rf $CBINDGEN_DIR
mkdir -p $CBINDGEN_DIR
cbindgen $BASE2/src/lib.rs --output $CBINDGEN_DIR/${LIBID}.h --lang c
LIBDIR=$APPMAIN/java/$LIBID
echo 'library is called' $LIBID ', stored in' $LIBDIR
rm -rf $LIBDIR
mkdir -p $LIBDIR
swig -outdir $LIBDIR -java -package $LIBID $BASE2/$LIBID.i
SODIR=$APPMAIN/jniLibs/arm64-v8a
rm -rf $SODIR
mkdir -p $SODIR
SONAME=lib${LIBID}.so
echo 'dynamic library to' $SODIR/$SONAME
$CC -target $ARCH-clang -nostartfiles -shared $BASE2/${LIBID}_wrap.c $RUSTEX_ANDR -lm -lz -o $SODIR/$SONAME -I $BASE2 -fPIC
最后,我恢复到了 NDK 22 版本。
我之前的版本使用了版本 22,并且可以正常工作。所以我从 Android 网站下载了 NSK 版本 22 并重新构建了我的应用程序,它成功了。
这是一种解决方法,而不是正确的解决方案,但它现在对我有用。