android - 如何使用 Android NDK 的共享库(C 库添加到 C++)

标签 android android-ndk

所以。我在 C 中找到了这个名为 fastpbkdf2 的库,并从中创建了共享库。

我创建了一个小的 C++ fragment ,它将调用库中的方法之一。但我不断得到

error: undefined reference to ...

我搜索了很多东西,尝试了一切,但没有运气。我可能在这里遗漏了一些明显的东西。 (哦,我从来没有为 C++ 或 C 编程过,所以这可能是问题所在)

所有文件都在同一个文件夹中。

这是Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE           := pbkdf2core
LOCAL_SRC_FILES        := libpbkdf2core.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := pbkdf2
LOCAL_SRC_FILES := pbkdf2.cpp
LOCAL_SHARED_LIBRARIES := pbkdf2core
include $(BUILD_SHARED_LIBRARY)

这是我在 C++ 中的尝试:

#include <jni.h>
#include "native.h"
#include <pbkdf2core.h>

extern "C"{
    JNIEXPORT jbyteArray JNICALL Java_com_package_generatePBKDF2key
    (JNIEnv * env, jclass cls, jbyteArray password, jbyteArray salt, jint iterations)
    {
            uint8_t * out;

            fastpbkdf2HmacSha1(jbyteArrayToString(env, password), 
                env->GetArrayLength(password), 
                jbyteArrayToString(env, salt), 
                env->GetArrayLength(salt), 
                (int) iterations, out, 32);


            jbyteArray bytes = env->NewByteArray(32); 
            env->SetByteArrayRegion(bytes, 0, 32, (jbyte*)out); 
            return bytes;
            //return password; --> running only this works ok
    }

    uint8_t* jbyteArrayToString(JNIEnv* env, jbyteArray barr)
    {
           uint8_t* rtn = NULL;
           jsize alen = env->GetArrayLength(barr);
           jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
           if (alen > 0)
           {
                     rtn = (uint8_t*)malloc(alen + 1);
                     memcpy(rtn, ba, alen);
                     rtn[alen] = 0;
           }
           env->ReleaseByteArrayElements(barr, ba, 0);
           return rtn;
    }

    //commenting out "bad" code, and running only this really works
    JNIEXPORT jint JNICALL Java_com_package_getNum(JNIEnv * env, jclass cls){
        return 1;
    }
}

和pbkdf2core.h:

#include <jni.h>
#include <stdlib.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif
void fastpbkdf2HmacSha1(const uint8_t *pw, size_t npw,
                          const uint8_t *salt, size_t nsalt,
                          uint32_t iterations,
                          uint8_t *out, size_t nout);
#ifdef __cplusplus
}
#endif

当我跳过“错误”代码时,一切正常(我可以运行其他方法,或者从第一个开始返回任何内容,因此所有其他设置应该都正常)。

如果我更改 header 中的任何内容,我会收到不同的错误(未声明)。我在这里错过了什么? (哦。我正在使用的库是在 C 中。

编辑:

这是我得到的错误:

[armeabi] Compile++ thumb: pbkdf2 <= pbkdf2.cpp
[armeabi] SharedLibrary  : libpbkdf2.so
/Users/.../src/main/jni/pbkdf2.cpp:15: error: undefined reference to 'fastpbkdf2HmacSha1'
collect2: error: ld returned 1 exit status
make: *** [/Users/.../src/main/obj/local/armeabi/libpbkdf2.so] Error 1

哦。我也试过

LOCAL_ALLOW_UNDEFINED := true

构建确实顺利(很明显),但随后出现应用程序运行时错误:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "fastpbkdf2HmacSha1"

最佳答案

看起来链接器在您的源代码和共享库中找不到方法 fastpbkdf2HmacSha1。通过强制它忽略问题(例如使用 LOCAL_ALLOW_UNDEFINED 标志),您可以在运行时简单地移动问题。这就是您收到 UnsatisfiedLinkError 的原因(VM 尝试加载缺少依赖项的库,但加载失败)。

首先,我会确保您使用的库是正确的。您需要查看 libpbkdf2core.so 以查找缺少的符号 (fastpbkdf2HmacSha1)。您可以使用 readelf 和 nm 来执行此操作。如果你有调试 .so,Nm 会显示符号,而 readelf 是一个更强大的工具。

要从 .so 中获取符号表,请执行以下操作:

readelf -Ws libpbkdf2core.so | grep fastpbkdf2HmacSha1

如果该符号不存在,您的 .so 是否已损坏或您使用的是错误的 .so?

关于android - 如何使用 Android NDK 的共享库(C 库添加到 C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37494767/

相关文章:

android - 如何使用 Gradle NDK build 为主机编译?

android - ProgressDialog 不想更新消息

java - Android 中 LocationManager 的 requestLocationUpdates 到底是如何工作的?

android - 删除选定行后的 ListView 动画行

javascript - 在 ScrollView 的 onscroll 属性中调用函数

android - gethostbyname 失败并出现错误 111 (ECONNREFUSED)

android - Surfaceflinger 测试程序

Cygwin 中的 Android NDK 构建错误

android - Google Play 不过滤 x86 设备

android - Environment.getExternalStoragePublicDirectory 提供内部存储