Reputation: 3196
I've got a shared library file, faceblaster-engine.so
, compiled for arm-linux-androideabi
, placed in the jniLibs folder for Android Studio. I've also got a simple cpp file in the jni folder.
My library is written in Rust, so I have no header files, and I'd like to call functions inside of it through the cpp file, but can't seem to get the library to link correctly. To test, I've made a simple function:
Rust
#[no_mangle]
pub extern fn rust_test() -> c_int {
82 as c_int
}
C++
extern "C" {
// Test for calling rust function
int rust_test();
jint
Java_com_fureality_faceblaster_MainActivity_testRustLaunch(JNIEnv* env, jobject thiz)
{
return rust_test();
}
} // End extern
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := faceblaster-engine
LOCAL_SRC_FILES := ../jniLibs/$(TARGET_ARCH_ABI)/libfaceblaster-engine.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := faceblaster
LOCAL_SRC_FILES := gl-tests.cpp
LOCAL_SHARED_LIBRARIES := faceblaster-engine
include $(BUILD_SHARED_LIBRARY)
Error
/home/nathan/Development/projects/faceblaster-android/app/src/main/jni/gl-tests.cpp
Error:(23) undefined reference to `rust_test'
Error:error: ld returned 1 exit status
make: *** [/home/nathan/Development/projects/faceblaster-android/app/build/intermediates/ndk/debug/obj/local/arm64-v8a/libfaceblaster.so] Error 1
Error:Execution failed for task ':app:compileDebugNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
/home/nathan/Development/bin/android-ndk-r10d/ndk-build NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=/home/nathan/Development/projects/faceblaster-android/app/build/intermediates/ndk/debug/Android.mk APP_PLATFORM=android-21 NDK_OUT=/home/nathan/Development/projects/faceblaster-android/app/build/intermediates/ndk/debug/obj NDK_LIBS_OUT=/home/nathan/Development/projects/faceblaster-android/app/build/intermediates/ndk/debug/lib APP_ABI=all
Error Code:
2
Output:
/home/nathan/Development/projects/faceblaster-android/app/build/intermediates/ndk/debug/obj/local/arm64-v8a/objs/faceblaster//home/nathan/Development/projects/faceblaster-android/app/src/main/jni/gl-tests.o: In function `Java_com_fureality_faceblaster_MainActivity_testRustLaunch':
/home/nathan/Development/projects/faceblaster-android/app/src/main/jni/gl-tests.cpp:23: undefined reference to `rust_test'
collect2: error: ld returned 1 exit status
make: *** [/home/nathan/Development/projects/faceblaster-android/app/build/intermediates/ndk/debug/obj/local/arm64-v8a/libfaceblaster.so] Error 1
I dunno if my makefile isn't being picked up, or if it is correct? Anyone have an idea on how to properly link against this .so file and register functions I'd like to use?
Thanks in advance for any help!
Edit - Added Java source and rust code compilation method
Java
public class MainActivity extends Activity {
// External libraries to load
static {
System.loadLibrary("faceblaster-engine");
System.loadLibrary("faceblaster");
}
// External functions to register
public native int testRustLaunch();
@Override
protected void onCreate(Bundle savedInstanceState) {
// Other stuff omitted for brevity
Log.d(TAG, "Testing call...");
int test = testRustLaunch();
Log.d(TAG, "Received: " + test);
}
}
Rust Compilation
cargo build --target=arm-linux-androideabi
# /project/.cargo/config file
[target.arm-linux-androideabi]
linker = "/opt/ndk_standalone/bin/arm-linux-androideabi-gcc"
# Cargo.toml
[lib]
name = "faceblaster-engine"
crate_type = ["dylib"]
Edit 2
I've edited by build.gradle
script, and my I know my Android.mk is being read and used now, but I am still getting the same compilation error :(
Edit 3
Turns out both of the answers below helped in solving the issue. It was mainly in part of Android Studio not picking up my makefile, the rust code not being declared properly as #[no_mangle] pub extern
and my makefile being all jacked up.
Upvotes: 3
Views: 1860
Reputation: 13317
Your Android.mk
doesn't specify that the JNI wrapper actually should try to link to faceblaster-engine - the LOCAL_SHARED_LIBRARIES
line instead says it should link to itself. Change it to LOCAL_SHARED_LIBRARIES := faceblaster-engine
and it should hopefully work better.
Then to actually load it at runtime, you need to load the libraries in reverse dependency order, i.e.:
System.loadLibrary("faceblaster-engine");
System.loadLibrary("faceblaster");
Upvotes: 2
Reputation: 430574
Give this a shot:
#[no_mangle]
pub extern fn rust_test() -> i32 {
82 // Note simplified implementation
}
The specific thing to try is #[no_mangle]
and pub
. pub
will mark the function as being callable from outside the compiled library. #[no_mangle]
instructs the compiler to not change the function name, so that the exported symbol will be the literal rust_test
.
I also took the liberty of making the actual method body more idiomatic.
Another note is that you should match your Rust and C types more closely. If you want to use an int
in C, you should use the Rust type c_int
. C's int
is allowed to change size depending on your platform! You could also use a int32
in Rust, but then you should use something like int32_t
in C.
Upvotes: 4