2015-01-27 88 views
3

我有一个共享库文件faceblaster-engine.so,编译为arm-linux-androideabi,位于Android Studio的jniLibs文件夹中。我在jni文件夹中也有一个简单的cpp文件。在Android Studio中链接无NDK标头的共享对象库

我的库是用Rust编写的,所以我没有头文件,我想通过cpp文件调用它里面的函数,但似乎无法使库正确链接。为了测试,我做了一个简单的函数:

#[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) 

错误

/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 

我不知道如果我的生成文件没有被拾起,或者如果它是正确的吗?任何人都有关于如何正确链接这个.so文件和注册我想使用的函数的想法?

在此先感谢您的帮助!

编辑 - 添加Java源和防锈代码编制方法


的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); 
    } 
} 

锈编译

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"] 

编辑2


我已经build.gradle脚本编辑,我知道我正在读,现在用我的Android.mk,但我仍然得到同样的编译错误:(

编辑3


原来这两个问题的答案在下面帮助解决这个问题。它主要是Android Studio的一部分,没有选择我的makefile文件,防火墙代码没有正确声明为#[no_mangle] pub extern,我的makefile文件全部被封装起来。

+0

或许,这将是很好的说明你是如何编译锈代码的(共享? ) 图书馆。 – Shepmaster 2015-01-27 01:45:37

+0

@Shepmaster谢谢你指出,编译笔记已被添加:) – nathansizemore 2015-01-28 01:48:59

+0

在哪个阶段你的错误发生?你能否告诉我们编译C++ shim的时候?它在运行时吗?还有一点呢?有没有办法在编译/链接阶段获得详细输出? – Shepmaster 2015-01-28 02:02:04

回答

2

Android.mk没有指定JNI封装实际上应该尝试链接到faceblaster - 引擎 - LOCAL_SHARED_LIBRARIES线,而不是说,应该链接到自己。将其更改为LOCAL_SHARED_LIBRARIES := faceblaster-engine,它应该可以更好地工作。

那么实际上在运行时加载它,你需要加载库以相反的依赖顺序,即:

System.loadLibrary("faceblaster-engine"); 
System.loadLibrary("faceblaster"); 
+0

感谢您指出,但改变也没有解决它。我开始认为Android Studio甚至没有读取生成文件,因为我只是输入了一堆垃圾,结果是一样的...... :( – nathansizemore 2015-01-28 01:53:26

+0

我看到你做了另一个编辑,说它现在实际上使用了'Android.mk',你不应该有'LOCAL_SHARED_LIBRARIES:= $(TARGET_ARCH_ABI)/libfaceblaster-engine.so '',你应该有'LOCAL_SHARED_LIBRARIES:= faceblaster-engine',就像我在答案中写的那样。你应该保留'faceblaster-engine'预构建模块的声明的其余部分('include $(CLEAR_VARS) LOCAL_MODULE: = faceblaster-engine LOCAL_SRC_FILES:= $(TARGET_ARCH_ABI)/libfaceblaster-engine.so include $(PREBUILT_SHARED_LIBRARY)')就像您以前那样。 – mstorsjo 2015-01-28 06:50:19

4

给这一个镜头:

#[no_mangle] 
pub extern fn rust_test() -> i32 { 
    82 // Note simplified implementation 
} 

具体的事情是尝试#[no_mangle]pubpub会将该函数标记为可从编译库外部调用。#[no_mangle]指示编译器不更改函数名称,以便导出的符号将为文字rust_test

我也冒昧地让实际的方法体更加地道。

另一个需要注意的是,你应该更紧密地匹配你的Rust和C类型。如果你想在C中使用int,你应该使用Rust类型c_int。 C的int被允许根据您的平台更改大小!你也可以使用在锈int32,但你应该在C.使用类似int32_t

+0

谢谢指出!不幸的是,仍然得到相同的错误信息:( – nathansizemore 2015-01-28 01:44:46