Android NDK/JNI:构建依赖其他共享库的共享库

 2023-01-19    331  

问题描述

我正在编写一个Android应用程序,该应用希望将JNI调用到使用NDK内置的共享库中.诀窍是此共享库提供的共享库调用函数.其他共享库是在其他地方编译的C库.

这是我尝试的:

Android NDK/JNI:构建依赖其他共享库的共享库

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

尝试#1 android.mk:只是告诉它libs在哪里

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.

来到这里,我发现了这个:

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

说我需要在所有必要的库上致电负载库.太好了!

尝试#2第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:使用预编译的静态静态库链接

这是关于静态库的,但也许我有类似的问题.要点是我需要为每个库声明一个模块.所以我的新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 我尝试运行它时会收到以下消息(告诉我loadLibrary打开了support_lib1和2:

尝试加载lib/data/app-lib/com.example.tst/libsupport_lib1.so
添加共享lib/data/app-lib/com.example.tst/libsupport_lib1.so
在/data/app-lib/com.example.tst/libsupport_lib1.so中找到未找到的jni_onload.

但是…
dlopen失败:无法找到符号func_that_exists_in_libsupport_lib.so so libnative_lib.so

引用

编辑:尝试5:使用prebuilt_shared_library

所以我发现了这个:
如何将Pre prenuilt共享库链接到Android NDK项目?

这似乎正是我要问的.他们的答案似乎是”不使用” 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-prepuilt’).这不需要对应于预制库本身的名称.

将您提供的预制库的路径分配给local_src_files.像往常一样,路径相对于您的local_path.

包括prebuilt_shared_library,如果您提供共享的库,而不是build_shared_library.对于静态,请使用prebuilt_static_library.
预制的模块不会构建任何东西.但是,您的预制共享库的副本将被复制到$ project/obj/local中,另一个将被复制并剥离为$ project/libs/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.

sooooo ….现在怎么了?

推荐答案

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

如果您将support_lib1.so重命名为libsupport_1.so和support_lib2.so libsupport_2.so,然后将这两个文件放入jni/lib目录中,那么您的尝试#5 将与较小的更改一起使用:

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.

ps 不要忘记更新Java侧:

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

其他推荐答案

不确定这是否正是您所在的位置,但这是我对这些事情的了解.

  1. 使每个预制的诽谤都有自己的单独的makefile. android.mk中的多个目标往往会变得杂乱.悲伤.
  2. 使用$(call import-add-path)和$(call import-module)
  3. 包括每个制作文件

  4. 使用LOCAL_EXPORT_变量家族从预制的制作文件中尽可能多地导出.

预先构建的共享库android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := my_module_name

MY_LIBRARY_NAME := shared_library_name

### export include path
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include

### path to library
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(MY_LIBRARY_NAME).so

### export dependency on the library
LOCAL_EXPORT_LDLIBS := -L$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/
LOCAL_EXPORT_LDLIBS += -l$(MY_LIBRARY_NAME)

include $(PREBUILT_SHARED_LIBRARY)

这是假设预建的诽谤生活在像这样的dir结构中

+ SharedProjectFolderName
+--- Android.mk
+--- include/
+-+- libs/$(TARGET_ARCH_ABI)/
  |- libshared_library_name.so

如果您不为多个ABI构建,我想您可以将其排除在外

项目的android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := my_jni_module

## source files here, etc...

### define dependency on the other library
LOCAL_SHARED_LIBRARIES := my_module_name

include $(BUILD_SHARED_LIBRARY)

$(call import-add-path,$(LOCAL_PATH)/path/to/myLibraries/)
$(call import-module,SharedProjectFolderName)
$(call import-module,AnotherSharedProject)

我建议您将所有共享库放在一个文件夹中.当您说$(call import-module,SharedProjectFolderName)时,它会寻找一个沿着搜索路径包含Android.mk的文件夹(import-add-path)

顺便说一句,您可能不应该指定LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib.它应该本身从NDK找到适当的Libs.添加更多的链接器路径可能会混淆它.适当的方法是将接头路径导出为子模块的标志.

另外,您可以使用ndk-build V=1获取有关为什么找不到路径等的大量信息

其他推荐答案

-l选项为链接器提供了一个目录路径来查找库. -l选项为链接器提供了一个库的文件名来链接.库文件名必须以” lib”开头.您的库应命名为libsupport_lib1.so和libsupport_lib2.so.如果您这样做,那么这可能是您应该做的(替换尝试#1):

LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog -lsupport_lib1 -lsupport_lib2
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib

链接器将使用” lib”使用-l指定的库名称,并带有” .so”后缀. (为什么您有-l $(sysroot)/../usr/lib?)

我相信尝试#1和#2失败了,因为您没有将库将其链接到可执行文件中 – 在-L选项中未提及它们.顺便说一句,您可以自己验证这一点.解压缩.APK文件,然后查看LIB目录和子目录.您的.SO文件中吗?

查看错误:

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

您可以提供整个消息吗? dlopen()将库加载并链接到运行过程中.

以上所述是小编给大家介绍的Android NDK/JNI:构建依赖其他共享库的共享库,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/25762.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。