【问题标题】:Android native runtime fails to load symbols even though they are actually found in the loaded .so filesAndroid 本机运行时无法加载符号,即使它们实际上是在加载的 .so 文件中找到的
【发布时间】:2017-10-24 06:26:59
【问题描述】:

我已经使用 NDK v15.2 编译了 ffmpeg v3.4,并且正在创建一个名为 ffmpeg-jni 的包装器库。

static {
    try {
        System.loadLibrary("avutil");
        System.loadLibrary("avcodec");
        System.loadLibrary("avformat");
        System.loadLibrary("swscale");
        System.loadLibrary("avfilter");
        System.loadLibrary("ffmpeg-jni"); // Exception here line#101
        loadedLibraries = true;
    } catch (Throwable e) {
        e.printStackTrace();
    }
}

下面是加载我的包装库时抛出的异常。

10-24 11:12:13.819 21499-21499/com.myeglu.android.canary.staging W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "av_register_all" referenced by "/data/app/com.myeglu.android.canary.staging-2/lib/arm/libffmpeg-jni.so"...

但是,令我惊讶的是,这个函数是在 libavformat.so 中定义的,它加载成功;从nm tool output可以清楚地看出,av_register_all() 函数是在 libavformat.so 中定义的 (T)

这里是所有在运行时难以实现和平的预构建库的链接。 (除了 ffmpeg 库之外,还有一些其他库)

https://drive.google.com/drive/folders/0B20ExoMyOP_UeDhNdmwzc2tjR3M?usp=sharing

有人帮助我了解在这种情况下我可能会丢失什么。感谢您的宝贵时间。

【问题讨论】:

  • 如果库不在您项目的正确文件夹中,它将不会链接它们。例如:app/jniLibs/armeabi-v7a 并且你的 gradle 脚本需要引用它们,你没有在这里显示。
  • 库被正确地塞进了 apk,目前只有一个变种 armeabi。在运行时,它也能够正确加载它们。加载所有其他依赖库后出现异常。
  • 您的 av-lib 属于 armeabi-v7a,而不是 armeabi。因此,如果您为 armeabi 构建 libffmpeg-jni.so,这可能会导致加载 lib 时出现问题。

标签: android c++ ffmpeg android-ndk


【解决方案1】:

首先,您应该以正确的顺序明确列出所有需要的库,或者让系统解决依赖关系(如果您的平台至少是 Lollipop)。

具体来说,libavcodec 需要 libswresample

但是 ffmpeg-jni 似乎没有正确构建。它的Dynamic部分只列出了

0x00000001 (NEEDED) Shared library: [libandroid.so]
0x00000001 (NEEDED) Shared library: [libjnigraphics.so]
0x00000001 (NEEDED) Shared library: [libavcodec.so]
0x00000001 (NEEDED) Shared library: [liblog.so]
0x00000001 (NEEDED) Shared library: [libc.so]

另外,.dynsym 表包含

 5: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND av_register_all

我希望相反,

 5: 00000000     0 FUNC    GLOBAL DEFAULT  UND av_register_all@LIBAVFORMAT_57 (4)

请注意,avcodec_find_decoder 的符号类型和来自您库中 libavcodec.so 的其他引用是正确的。

您可以将LOCAL_ALLOW_UNDEFINED_SYMBOLS=true 用于libffmpeg-jni.so吗?

更新:实际上,cmake使用Android工具链准备的CMAKE_SHARED_LINKER_FLAGS--no-undefined传递给链接器;通过覆盖此变量,您有效地允许未定义的符号(并丢失了一些针对 Android 调整的其他重要标志)。底线是,覆盖 CMAKE 标准变量是危险的。

【讨论】:

  • 我已将 libavcodec.so 设置为依赖于我的 cmake 脚本。这又取决于 libavformat.so、libswscale.so、libavutil.so、libavcodec.so 和 libavfilter.so;在编译期间,这些文件都可以使用 cmake 外部构建获得,我可以从我的 IDE 导航到适当的头文件。它们也隐藏在 APK 中,并在运行时可供加载。但是在加载 libffmpeg-jni.so 时链接没有正确解析。
  • 找到了。我必须将所有依赖库添加为我的 jni 包装器的依赖项。 Libs 不会传递地打包。
  • 我在这里创建了早期设置的要点。 gist.github.com/Gopinathp/4fc523ec922117f2f3928eef2fb2e4fa
  • 当我们为 Android 链接时,我们使用 clang 或(现已弃用)gcc 来调用链接器。一些标志,如-v,是直接传递的; clang 无法识别其他链接器标志,例如 --as-needed ,我们需要 -Wl, 前缀来帮助它。
  • --as-needed 告诉链接器只在 ELF 标头中写入所需的外部共享库的名称。在您的情况下,它可能会从 libffmpeg-jni.so 中保存的列表中删除 libm.so
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-04
相关资源
最近更新 更多