【发布时间】:2014-03-22 06:39:21
【问题描述】:
我正在编写一个 Android 应用程序,它希望将 JNI 调用放入使用 NDK 内置的共享库中。诀窍是这个共享库调用其他共享库提供的函数。其他共享库是在别处编译的 C 库。
这是我尝试过的:
我的环境: 我在 Eclipse 中工作。我添加了本机支持并拥有一个 jni 库。在那个库中,我有我的代码和一个 \lib 目录,我在其中复制了我的其他 .so 文件。
尝试 #1 Android.mk:告诉它库在哪里
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2
include $(BUILD_SHARED_LIBRARY)
这构建得很好,但是当我尝试运行时,我收到错误,表明 dlopen(libnative_lib) 失败,因为它无法加载 libsupport_lib1。
来到这里我发现了这个:
Can shared library call another shared library?
这表示我需要在所有必要的库上调用加载库。太好了!
尝试 #2 首先打开每个库
static {
System.loadLibrary("support_lib1");
System.loadLibrary("support_lib2");
System.loadLibrary("native_lib");
}
同样,这构建得很好,但是当我运行时出现新错误:
无法加载 libsupport_lib1。 findLibrary 返回 null。
现在我们正在取得进展。它不能将库加载到目标。
尝试 #3 将 .so 文件复制到 project/libs/armeabi 中
没用。当 Eclipse 构建时,它删除了我放在那里的文件。
尝试 #4 为每个库创建一个新模块
然后我发现了这个:
Android NDK: Link using a pre-compiled static library
这是关于静态库的,但也许我遇到了类似的问题。要点是我需要为每个库声明一个模块。所以我的新 Android.mk 看起来像这样:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib1.so
include $(BUILD_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib2.so
include $(BUILD_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2
include $(BUILD_SHARED_LIBRARY)
这构建!更棒的是,armeabi 现在有了 sos!甚至 BETTER 我在尝试运行它时收到以下消息(告诉我 support_lib1 和 2 已由 LoadLibrary 打开:
尝试加载 lib /data/app-lib/com.example.tst/libsupport_lib1.so 添加了共享库 /data/app-lib/com.example.tst/libsupport_lib1.so 在 /data/app-lib/com.example.tst/libsupport_lib1.so 中找不到 JNI_OnLoad,跳过初始化
然后…… dlopen 失败:找不到 libnative_lib.so 引用的符号 func_that_exists_in_libsupport_lib.so
编辑:尝试 5:使用 PREBUILT_SHARED_LIBRARY
所以我发现了这个: How can i Link prebuilt shared Library to Android NDK project?
这似乎正是我要问的。他们的回答似乎是'不要使用'build_shared_library',而是'使用PREBUILT_SHARED_LIBRARY
好的,我们试试。
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
构建...失败!该版本现在抱怨缺少符号。
编辑:尝试 6:展平一切
所以我回到了 NDK 中的预构建文档。它说:
每个预构建库必须声明为构建系统的单个独立模块。这是一个简单的示例,我们假设文件“libfoo.so”与下面的 Android.mk 位于同一目录中:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
请注意,要声明这样一个模块,您实际上只需要以下内容:
为模块命名(此处为“foo-prebuilt”)。这不需要与预建库本身的名称相对应。
将您提供的预构建库的路径分配给 LOCAL_SRC_FILES。像往常一样,路径是相对于您的 LOCAL_PATH 的。
如果您提供共享库,请包括 PREBUILT_SHARED_LIBRARY,而不是 BUILD_SHARED_LIBRARY。对于静态的,使用 PREBUILT_STATIC_LIBRARY。 预构建的模块不会构建任何东西。但是,您的预构建共享库的副本将被复制到 $PROJECT/obj/local,另一个将被复制并剥离到 $PROJECT/libs/。
因此,让我们尝试将所有内容展平以匹配琐碎的示例。我从他们舒适的 /lib 文件夹中复制了我的库,并将它们放在 jni 根目录中。然后我这样做了:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := support_lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := support_lib2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
和...同样的错误。此外,我绝对不会看到库文件被复制到 $PROJECT/obj/local。
太好了....现在呢?
【问题讨论】:
-
一条线索! eclipse 放入我 armeabi 的库不是我试图提供的库的副本。 armeabi 中的 libsupport_lib1.so 与 jni/lib 中的 libsupport_lib1.so 大小不同...所以我做错了什么没有将其复制到正确的位置?
-
很不幸,库不能直接放在 libs/ 中而没有 eclipse 在构建时将它们丢弃.. 会简单得多.. 我在任何地方都找不到解决方法。
-
嗨,我也有同样的问题。你解决了吗?如果是这样,你能给我你的解决方案吗?
标签: android linker android-ndk java-native-interface shared-libraries