2023-01-19 331
我正在编写一个Android应用程序,该应用希望将JNI调用到使用NDK内置的共享库中.诀窍是此共享库提供的共享库调用函数.其他共享库是在其他地方编译的C库.
这是我尝试的:
我的环境:
我在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");
}
不确定这是否正是您所在的位置,但这是我对这些事情的了解.
包括每个制作文件
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构建,我想您可以将其排除在外
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/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态