java.lang.UnsatisfiedLinkError:dlopen失败:找不到库

时间:2018-08-29 11:43:35

标签: android build cmake shared-libraries android-gradle-3.1.0

我正在尝试使用cmake构建我的Android(本机)项目(将其从gradle实验性插件中迁移出来,该插件曾经用来构建并正常运行)。

我有一些本机代码(将其称为“ a”),它使用了另一个外部预建库代码(将其称为“ b”),并且我将两者链接在一起,如下所示: (根据https://developer.android.com/studio/projects/configure-cmake

cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -frtti -fno-common -fexceptions")

include_directories(
#a's include files' paths
#b's include files' paths)

file(GLOB_RECURSE A_SOURCES
#a's source files' paths)

add_library(a_lib SHARED ${A_SOURCES})
add_library(b_lib SHARED IMPORTED)
set_target_properties(b_lib PROPERTIES IMPORTED_LOCATION "b's .so path")
target_link_libraries(a_lib b_lib)

我完成了编译和链接步骤,android studio继续在设备上安装APK。但是,启动后,该应用程序将在logcat中冻结,并显示以下内容:

E/ExceptionHandler: Uncaught Exception java.lang.UnsatisfiedLinkError: dlopen failed: library "libb_lib.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:989)
at java.lang.System.loadLibrary(System.java:1530)
at com.mm.projectname.model.libloadingclassname.<clinit>(libloadingclassname.java:99)

我知道这是因为b_lib的.so在apk中不存在。而且我可以在a的共享库中看到b的符号以及a的符号。

所以我的问题是我怎么能

  1. 要么将我的预构建b的.so打包到apk中
  2. 或阻止系统在libs文件夹中查找b.so并使其仅在a的.so中查找b的符号。

我搜索了很多类似的帖子和问题(例如onetwo),但是我什么都无法工作。我真的在寻找实现此目的的正确方法-将来不会造成问题(例如更改targetSDKversion)。我还尝试使用最新的ndk版本构建预构建的lib。

我可能犯了一个非常小的错误,如果有人可以指出,我将不胜感激。

预先感谢

2 个答案:

答案 0 :(得分:0)

有点晚了,但是其他人可能会感兴趣(甚至是op)。

我的情况与操作员相同,并且尝试了许多不同的操作。其中之一是尝试使用较早版本的NDK编译项目(我认为r14b,但我不确定)。我遇到了另一个错误,并设法在{Invalid DT_NEEDED Entries“和” Missing SONAME“部分中详细介绍了here的问题。此外,该问题在此特定的question中进行了描述,并且收到了适当的答案。

如果您不能重新编译用于包括SONAME的共享库,就像我的情况一样,您可以做以下我做过并且设法成功的事情:

  • 将该库包含在项目树的jniLibs文件夹中,因此该库打包在您的APK中,但不要链接到它。
  • 使用here中所述的任何方法来查找要合并的功能的符号。
  • 在C ++代码中创建相应函数的函数指针。
  • 在运行时加载共享库并映射到那些函数。

示例代码

标题

private:

typedef uint32_t (*InitX_t)();
typedef uint32_t (*DoX_t)();
typedef uint32_t (*GetX)(uint32_t, char*);

InitX_t InitX;
DoX_t DoX;
GetX_t GetX;

CPP

void *handle = dlopen("libMyLib.so", RTLD_NOW);

if(handle == nullptr)
{
    __android_log_print(ANDROID_LOG_INFO, "My Class", "Could not load library");
}
else
{
    __android_log_print(ANDROID_LOG_INFO, "My Class", "Library loaded");
}

InitX = (InitX_t)dlsym(handle, "InitX_SYMBOL");
ScanX = (ScanX_t)dlsym(handle, "ScanX_SYMBOL");
GetX = (GetX_t)dlsym(handle, "GetX_SYMBOL");

if(ScanX == nullptr || GetX == nullptr || InitX == nullptr)
{
    __android_log_print(ANDROID_LOG_INFO, "My Class", "Could not load functions.");
}

如果操作正确,则现在应该可以照常使用这些功能。不过,我了解,如果您是初学者,这并不是最简单的过程。

答案 1 :(得分:0)

  1. 在您的应用目录中创建一个jniLibs文件夹。
  2. 根据架构命名另一个文件夹。
  3. 将您的.so文件存储在此文件夹中。