Android NDK - 使两个本机共享库相互调用 [英] Android NDK - make two native shared libraries calling each other

查看:38
本文介绍了Android NDK - 使两个本机共享库相互调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试构建两个共享库浪费了半天时间,例如mod1mod2(Android NDK 将其编译为 libmod1.solibmod2.so),来自一个jni 文件夹和子文件夹,然后让 mod1 从 mod2 调用函数.很多关于如何使构建工作的答案,但随后运行时动态链接不起作用,应用程序在启动时崩溃.

Wasted half a day trying to build two shared libraries, e.g. mod1 and mod2 (which Android NDK compiles to libmod1.so and libmod2.so), from sources in a jni folder and sub-folders, then have mod1 call a function from mod2. Plenty of answers on how to make the build work, but then runtime dynamic linking was not working, the app crashed on startup.

决定把这个问题贴出来,马上回答,这样整个过程的Q和A就在一起了,希望别人不要浪费一天的时间再研究一下.

Decided to post this question and immediately answer it, so that Q and A to the whole process are together, and hopefully someone else won't waste a day researching it again.

推荐答案

正确的构建过程相对容易,我的问题是让 libmod1.so 依赖 libmod2.so 导致启动时链接不满意 - mod1 代码找不到 mod2共享库,即使它们都存在于最终 APK 中的同一文件夹中,位于 libs/armeabi、libs/x86 等下.但是,为了使我的回答完整:

The correct build procedure was relatively easy, my problem was that making libmod1.so dependent on libmod2.so caused unsatisfied links upon startup - mod1 code could not find mod2 shared library, even though both were present within the same folder in the final APK, under libs/armeabi, libs/x86 etc. However, to make my answer complete:

  • 将 C 或 C++ 源代码和头文件放在 Android 项目中 jni 目录的子目录下,例如文件夹 mod1/和 mod2/

  • Put your C or C++ sources and header files under sub-directories of jni dir in your Android project, e.g. folders mod1/ and mod2/

根据 NDK 指令,创建 Application.mk 文件,例如我的是:

Per NDK instructions, create Application.mk file, e.g. mine is:

NDK_TOOLCHAIN_VERSION=4.7
APP_PLATFORM := android-8
APP_ABI := armeabi armeabi-v7a x86

NDK_TOOLCHAIN_VERSION=4.7
APP_PLATFORM := android-8
APP_ABI := armeabi armeabi-v7a x86

  • 按照此模板创建 Android.mk:
  • LOCAL_PATH := $(call my-dir)
    包括 $(CLEAR_VARS)
    LOCAL_SHARED_LIBRARIES := mod2    # 这使得 libmod1.so 依赖于 libmod2.so
    LOCAL_MODULE := mod1
    LOCAL_SRC_FILES := mod1/file1.c
    LOCAL_SRC_FILES += mod1/file2.cpp
    ...
    包含 $(BUILD_SHARED_LIBRARY)    # 这实际上构建了 libmod1.so

    包括 $(CLEAR_VARS)
    LOCAL_MODULE := mod2
    LOCAL_SRC_FILES := mod2/file1.cc
    LOCAL_SRC_FILES += mod2/file2.cc
    ...
    包含 $(BUILD_SHARED_LIBRARY)    # 这将构建 libmod2.so

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SHARED_LIBRARIES := mod2    # this makes libmod1.so dependent on libmod2.so
    LOCAL_MODULE := mod1
    LOCAL_SRC_FILES := mod1/file1.c
    LOCAL_SRC_FILES += mod1/file2.cpp
    ...
    include $(BUILD_SHARED_LIBRARY)    # this actually builds libmod1.so

    include $(CLEAR_VARS)
    LOCAL_MODULE := mod2
    LOCAL_SRC_FILES := mod2/file1.cc
    LOCAL_SRC_FILES += mod2/file2.cc
    ...
    include $(BUILD_SHARED_LIBRARY)    # this builds libmod2.so

    就是这样,所有构建都没有抱怨 ndkbuild 脚本.您只需要一个 C 包装器就可以从 Java 调用一些函数.这是我的问题.因为我只有在 libmod1.so 中有可从 Java 调用的函数,所以我在 Java 中的 C 包装类是这样的:

    That's about it, all builds without complains with ndkbuild script. You only need a C wrapper to call some functions from Java. And here was my problem. Since I had functions callable from Java only in libmod1.so, my C wrapper class in Java was like:

    public class CWrapper {
        static {
            System.loadLibrary("mod1");
        }
        public static native int func1(String aParam);
        ...
    }
    

    这对我来说似乎完全合乎逻辑 - 我从 Java 调用 libmod1.so,所以我使用了 System.loadLibrary("mod1"),并且因为 libmod1.so 知道它依赖于 libmod2.so,并且两个文件都在同一个文件夹,libmod1 会知道如何查找和加载 libmod2,对吗?错误的!它在应用程序启动时因不满意的链接"而崩溃.确切的错误消息是:

    This seemed perfectly logical to me - I call to libmod1.so from Java, so I used System.loadLibrary("mod1"), and since libmod1.so knows it depends on libmod2.so, and both files are in the same folder, libmod1 will know how to find and load libmod2, right? Wrong! It was crashing upon app startup with "unsatisfied link". The exact error message was:

    java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libmod2.so" needed by "libmod1.so"; caused by load_library(linker.cpp:745): library "libmod2.so" not found
    

    我到处寻找更多代码添加到 Android.mk 以解决这个问题.终于尤里卡了!我修改了我的 CWrapper 类如下:

    I was searching everywhere for some more code to add to Android.mk to resolve this in vain. Finally Eureka! I modified my CWrapper class as follows:

    public class CWrapper {
        static {
            System.loadLibrary("mod2"); // must be first, as mod1 depends on mod2!
            System.loadLibrary("mod1");
        }
        public static native int func1(String aParam);
        ...
    }
    

    事情开始像魅力一样发挥作用......

    and things started working like a charm...

    格雷格

    这篇关于Android NDK - 使两个本机共享库相互调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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