关于链接器:使用Android Studio中的NDK将不带标题的共享对象库链接

Linking shared object library without headers with NDK in Android Studio

我有一个为arm-linux-androideabi编译的共享库文件faceblaster-engine.so,放在Android Studio的jniLibs文件夹中。我在jni文件夹中还有一个简单的cpp文件。

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

1
2
3
4
#[no_mangle]
pub extern fn rust_test() -> c_int {
    82 as c_int
}

C ++

1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
4
5
6
7
8
9
10
11
12
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)

错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/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

我不知道我的makefile没有被提取还是正确?有人对如何正确链接此.so文件和注册我要使用的功能有想法吗?

在此先感谢您的帮助!

编辑-添加了Java源代码和rust代码编译方法

爪哇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
    }
}

锈编译

1
2
3
4
5
6
7
8
9
10
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却全部被劫持了。


试一下:

1
2
3
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允许根据您的平台更改大小!您也可以在Rust中使用int32,但随后在C语言中应使用int32_t之类的东西。


您的Android.mk没有指定JNI包装器实际上应该尝试链接到faceblaster-engine-LOCAL_SHARED_LIBRARIES行表示应该链接到自身。将其更改为LOCAL_SHARED_LIBRARIES := faceblaster-engine,希望它可以更好地工作。

然后要在运行时实际加载它,您需要以相反的依赖关系顺序加载库,即:

1
2
System.loadLibrary("faceblaster-engine");
System.loadLibrary("faceblaster");