Android NDK/JNI:构建依赖于其他共享库的共享库 [英] Android NDK/JNI: Building a shared library that depends on other shared libraries

查看:151
本文介绍了Android NDK/JNI:构建依赖于其他共享库的共享库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个Android应用,该应用希望对使用NDK内置的共享库进行JNI调用.诀窍在于,此共享库调用了其他共享库提供的功能.其他共享库是已在其他位置编译的C库.

I am writing an android app that wants to make JNI calls into a shared library built in using the NDK. The trick is this shared library calls functions provided by OTHER shared libraries. The other shared libraries are C libraries that have been compiled elsewhere.

这是我尝试过的:

我的环境: 我正在Eclipse中工作.我添加了本机支持并拥有jni库.在该库中,我有我的代码和一个\ lib目录,在该目录中已复制了其他.so文件.

My Environment: I'm working in Eclipse. I've added native support and have a jni library. In that library I have my code and a \lib directory where I have copied my other .so files.

尝试排名第一的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.

This builds just fine, but when I try to run I get errors indicating that dlopen(libnative_lib) failed because it couldn't load libsupport_lib1.

来到这里,我发现了这一点:

Coming here I found this:

共享库可以调用另一个共享库吗?

这表示我需要在所有必需的库上调用加载库.太好了!

which said that I needed to call load library on all necessary libraries. Great!

尝试#2首先打开每个库

static {
    System.loadLibrary("support_lib1");
    System.loadLibrary("support_lib2");
    System.loadLibrary("native_lib");
}

同样,它构建的很好,但是当我运行时,我收到了一个新错误:

Again, this builds just fine, however when I run I get a new error:

无法加载libsupport_lib1. findLibrary返回null.

couldn't load libsupport_lib1. findLibrary returned null.

现在我们要去某个地方.它一定不能将库加载到目标.

Now we're getting somewhere. It must not be loading the libraries over to the target.

尝试#3将.so文件复制到project/libs/armeabi

没用.在Eclipse构建时,它删除了我放入其中的文件.

Didn't work. When Eclipse builds it deleted the files I dropped in there.

尝试#4为每个库创建一个新模块

所以我发现了这个:

Android NDK:使用预编译的静态库进行链接

这是关于静态库的,但是也许我遇到了类似的问题.要点是,我需要为每个库声明一个模块.所以我的新Android.mk看起来像这样:

It's about static libraries, but maybe I am having a similar problem. The gist is that I need to declare a module for each library. So my new Android.mk looks like this:

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!甚至更好,当我尝试运行它时也会收到以下消息(告诉我support_lib1和2已由LoadLibrary打开:

This builds! Even better, armeabi has the sos now! Even BETTER I get the following messages when I try to run it (telling me that support_lib1 and 2 were opened by 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,跳过init

Trying to load lib /data/app-lib/com.example.tst/libsupport_lib1.so added shared lib /data/app-lib/com.example.tst/libsupport_lib1.so no JNI_OnLoad found in /data/app-lib/com.example.tst/libsupport_lib1.so, skipping init

但是然后... dlopen失败:无法找到libnative_lib.so引用的符号func_that_exists_in_libsupport_lib.so

but then... dlopen failed: Could not locate symbol func_that_exists_in_libsupport_lib.so referenced by libnative_lib.so

尝试5:使用PREBUILT_SHARED_LIBRARY

所以我发现了这个: 如何将预构建的共享库链接到Android NDK项目?

So I found this: How can i Link prebuilt shared Library to Android NDK project?

这似乎正是我要的.他们的答案似乎是不使用'build_shared_library',而是'使用PREBUILT_SHARED_LIBRARY

which seems to be exactly what I'm asking. Their answer seems to be 'don't use 'build_shared_library' but instead 'use PREBUILT_SHARED_LIBRARY

好的,让我们尝试一下.

Okay, let's try.

 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)

构建...失败!该版本现在抱怨缺少符号.

Build... fails! The build complains about missing symbols now.

尝试6:拼合所有内容

所以我回到了NDK中的预建文档.它说:

So I went back to the prebuilts documentation in the NDK. It says:

每个预构建的库必须声明为构建系统的单个独立模块.这是一个简单的示例,其中我们假定文件"libfoo.so"与以下Android.mk位于同一目录中:

Each prebuilt library must be declared as a single independent module to the build system. Here is a trivial example where we assume that the file "libfoo.so" is located in the same directory than the Android.mk below:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)

请注意,要声明这样的模块,您实际上只需要以下内容:

Notice that, to declare such a module, you really only need the following:

为模块命名(此处为"foo-prebuilt").这不需要与预构建库本身的名称相对应.

Give the module a name (here 'foo-prebuilt'). This does not need to correspond to the name of the prebuilt library itself.

将要提供的预构建库的路径分配给LOCAL_SRC_FILES.和往常一样,该路径是相对于您的LOCAL_PATH的.

Assign to LOCAL_SRC_FILES the path to the prebuilt library you are providing. As usual, the path is relative to your LOCAL_PATH.

如果要提供共享库,请包括PREBUILT_SHARED_LIBRARY而不是BUILD_SHARED_LIBRARY.对于静态的,请使用PREBUILT_STATIC_LIBRARY. 预先构建的模块不会构建任何内容.但是,您的预建共享库的一个副本将被复制到$ PROJECT/obj/local,另一个将被复制并剥离到$ PROJECT/libs/.

Include PREBUILT_SHARED_LIBRARY, instead of BUILD_SHARED_LIBRARY, if you are providing a shared, library. For static ones, use PREBUILT_STATIC_LIBRARY. A prebuilt module does not build anything. However, a copy of your prebuilt shared library will be copied into $PROJECT/obj/local, and another will be copied and stripped into $PROJECT/libs/.

因此,让我们尝试将所有内容弄平,以匹配简单的示例.我从舒适的/lib文件夹中复制了库,并将它们放在jni根目录中.然后,我这样做了:

So let's try flattening everything out to match the trivial example. I copied my libraries out of their cozy /lib folder and put them in the jni root. I then did this:

 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.

and... same error. Moreover I'm most definitely NOT seeing library files getting copied to $PROJECT/obj/local.

sooooo ....现在怎么办?

sooooo.... now what?

推荐答案

您的问题在于命名约定. NDK和Android坚持要求共享库名称始终以 lib 开头.否则,这些库将无法正确链接,不能正确复制到libs/armeabi文件夹,也不能正确安装在设备上(正确复制到/data/data/package/lib目录.

Your problem is with the naming convention. NDK and Android insist on the shared library names to always begin with lib. Otherwise, the libraries will not be linked properly, and not copied to the libs/armeabi folder properly, and not installed on the device (copied to /data/data/package/lib directory properly.

如果将support_lib1.so重命名为libsupport_1.so,将support_lib2.so重命名为libsupport_2.so,并将这两个文件放在jni/lib目录中,则您的 Attempt#5 会稍作更改:

If you rename support_lib1.so to libsupport_1.so and support_lib2.so to libsupport_2.so, and put these two files in jni/lib directory, then your Attempt #5 will work with minor change:

LOCAL_PATH := $(call my-dir)

#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE           := support_lib1
LOCAL_SRC_FILES        := lib/libsupport_1.so
include $(PREBUILT_SHARED_LIBRARY)

#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE           := support_lib2
LOCAL_SRC_FILES        := lib/libsupport_2.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)

顺便说一句,我认为您不需要这个-L$(SYSROOT)/../usr/lib.

BTW, I don't think you need this -L$(SYSROOT)/../usr/lib.

PS 也不要忘记更新Java端:

PS Don't forget to update the Java side, too:

static {
    System.loadLibrary("support_lib1");
    System.loadLibrary("support_lib2");
    System.loadLibrary("native_lib");
}

这篇关于Android NDK/JNI:构建依赖于其他共享库的共享库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆