2015-01-27 154 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