【问题标题】:Android NDK: load_library: cannot locate srandAndroid NDK:load_library:找不到 srand
【发布时间】:2014-10-17 23:06:28
【问题描述】:

我有一个 android 项目,我在其中使用本机代码来处理 SIP(​​使用 libosip2 和 libeXosip2)。我的本机代码与库的源代码一起编译到一个模块中。

代码编译得很好,生成的库具有我期望它具有的所有符号,但是当我尝试加载生成的库时出现以下错误:

E/eXosip.loadLibrary(9210): java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1307]:  1941 cannot locate 'srand'...

我的 Application.mk 如下所示:

APP_STL         := gnustl_shared
APP_ABI         := armeabi-v7a
APP_CPPFLAGS    += -fexceptions

我确实使用 ndk-depends 检查了未捕获的依赖项,这给了我

libeXosip_jni.so
libstdc++.so
liblog.so
libgnustl_shared.so
libm.so
libdl.so
libc.so

添加 loadLibrary("gnustl_shared") 没有帮助(这是在“libs/armeabi-v7/”中也发现的唯一提到的库)。

我的 Android.mk:

LOCAL_PATH  := $(call my-dir)
$(shell (cd $(LOCAL_PATH); sh extract_stuff.sh; cd $(OLDPWD)))


include $(CLEAR_VARS)
OSIP        := libosip2-4.1.0
EXOSIP      := libeXosip2-4.1.0
LOCAL_MODULE    := eXosip

LOCAL_C_INCLUDES    := $(LOCAL_PATH)/$(OSIP)/include \
                       $(LOCAL_PATH)/$(EXOSIP)/include

LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%, %, $(wildcard $(LOCAL_PATH)/$(OSIP)/src/osipparser2/*.c)) \
                   $(patsubst $(LOCAL_PATH)/%, %, $(wildcard $(LOCAL_PATH)/$(OSIP)/src/osip2/*.c)) \
                   $(patsubst $(LOCAL_PATH)/%, %, $(wildcard $(LOCAL_PATH)/$(EXOSIP)/src/*.c))

LOCAL_CFLAGS += -DHAVE_FCNTL_H \
                -DHAVE_SYS_TIME_H \
                -DHAVE_STRUCT_TIMEVAL \
                -DHAVE_SYS_SELECT_H \
                -DHAVE_PTHREAD \
                -DHAVE_SEMAPHORE_H \
                -DENABLE_TRACE \
                -DOSIP_MT

include $(BUILD_STATIC_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE    := eXosip_jni
LOCAL_STATIC_LIBRARIES  := eXosip
LOCAL_LDLIBS := -llog 

LOCAL_C_INCLUDES := BackendData.h \
                    $(LOCAL_PATH)/$(EXOSIP)/include \
                    $(LOCAL_PATH)/$(OSIP)/include

LOCAL_SRC_FILES := eXosip.cpp \
                   eXosipCall.cpp

include $(BUILD_SHARED_LIBRARY)

C/C++ 不是我的刚毅,所以如果有人能启发我,我将非常感激 :) 作为替代方案,我的问题的解决方案也很好 ^^


更新 1

我将 eXosip/osip 库从我的代码中分离出来,将其编译成一个静态库。我还测试了创建一个共享库并从 Java 内部手动加载它,它失败并显示相同的错误消息。

更新 2

我尝试使用 gnustl_shared、静态和 stlport - 错误仍然存​​在。

【问题讨论】:

  • grep 你的各种 .so 文件并找出哪一个依赖于 srand。添加基于 Android 支持的实现/仿真,可能是不同的随机 AP。
  • 我仍然不知道它是什么,所以我会暂时搁置这个问题,看看是否有人能提出真正的解决方案。我现在可以将我的 NDK 从 r10 降级到 r9d。不知道有什么不同,好像只有我一个人经历过。
  • 两个关键问题:您使用的确切 NDK R10 下载是什么?接下来,find YOUR_NDK_R10_DIRECTORY -name "stdlib.h" | xargs grep "srand(" 的输出中是否有任何行没有指定“inline”?
  • 嗨,@Managarm,你还记得造成这种情况的根本原因吗?我正在努力弄清楚为什么会发生这种情况。在我的情况下,它是一个不同的函数,它是 libc 的一部分。怎么不见了?
  • @WindRider 在我的情况下,这是因为我使用的是 64 位 NDK。使用 32 位 NDK 对我有用。

标签: java android android-ndk sip unsatisfiedlinkerror


【解决方案1】:

srand 被定义为 inline

NDK/platforms/android-19/arch-arm/usr/include/stdlib.h:

static __inline__ void srand(unsigned int __s) {
    srand48(__s);
}

我不知道您的 extarct_stuff.sh 做了什么,而且我认为分离静态库(库)没有任何区别。但是在某处您使用的是非 NDK 标头(如果您在 Linux 上,可能是您的 /usr/include。您可以运行 ndk-build V=1 以查看运行编译器的所有实际命令,并检查是否在某处使用了一些意外的 -I。也许,srand 是在$(LOCAL_PATH)/$(OSIP)/include$(LOCAL_PATH)/$(EXOSIP)/include 的文件之一中定义的。

【讨论】:

  • 我检查并没有发现任何异常。我现在可以将 NDK 从 r10 降级到 r9d。感谢您的建议!
【解决方案2】:

感谢 Chris,我意识到自己的错误是使用了 用于 64 位设备的 NDK。虽然我无法使用最小示例(它似乎特定于 libosip2 和可能的其他示例)复制错误,但使用 32 位 NDK 解决了该问题。

感谢所有花时间评论和发布建议的人!

【讨论】:

  • 能给我NDK 32 r10b for mac的下载链接吗?
  • 这在当时可行,但它可能不是未来可行的路径,因为它意味着与过时的 NDK 版本相关联。我怀疑随着时间的推移,Michaël 提到在 android 目标设置之外的角色的答案会更有用。
  • 这个问题根本不是 libosip2 特有的。任何使用 srand 的库都会因旧的 Android 目标而不是较新的目标而失败。要将 libosip2 与任何 Android 目标一起使用,请参阅我的答案并使用 -DHAVE_LRAND48
【解决方案3】:

同样的问题也发生在 NDK64 r10b(2014 年 9 月)上的 int rand(void)int rand_r(unsigned int*) 函数上。要重现,只需编译随 NDK64 r10b 提供的任何示例,然后调用 int rand(void)int rand_r(unsigned int*).

在 NDK32 r10b 上,这些函数在 stdlib.h 中定义为 static __inline__,但在 NDK64 r10b 上没有。

使用 Managarm 提到的 NDK32 r10b 可以解决问题,但对于那些想要为 arm64-v8a 目标进行编译的人来说,这是一个障碍!

得出的结论是 NDK64 r10b 在这一点上存在错误。

可能的补丁:将 NDK64 r10b stdlib.h 中缺失函数的原始定义替换为 NDK32 r10b stdlib.h 中的 static。 例如:对于srand(),它会变成:

static __inline__ void srand(unsigned int __s)
{
        srand48(__s);
}

【讨论】:

  • 能给我NDK 32 r10b for mac的下载链接吗?
【解决方案4】:

对于那些在 NDK r10c 上遇到 srand/atof 问题时偶然发现此线程的人:确保将您的 android 目标设置为 19。然后您的应用应该可以在 Android 5 (21) 以及所有较低版本上运行。

如果您将 android 目标设置为 21,那么您的应用将只能在 Android 5 上运行。 但是,您的应用将不再适用于所有较低的 android 版本,因为找不到很多 stdlib 函数(如 srand/atof)。

亲切的问候, 迈克尔

【讨论】:

  • 相反,这是一个非常重要的答案。
【解决方案5】:

在 Android 上,osip2 应该使用 -DHAVE_LRAND48 编译。然后,osip2 将不再使用 srand。这将允许您使用任何目标编译 osip2 和 eXosip2。 lrand48 至少从 android-3 开始就存在。

这是我用来编译 osip2 和 eXosip2 的标志:

LOCAL_CFLAGS := -fPIC -DPIC -D_POSIX_SOURCE \
    -DHAVE_SEMAPHORE_H  -DOSIP___FLAGS \
    -DHAVE_PTHREAD \
    -DHAVE_PTH_PTHREAD_H \
    -DHAVE_SYS_TYPES_H \
    -DHAVE_SYS_STAT_H \
    -DHAVE_FCNTL_H \
    -DHAVE_CTYPE_H \
    -DHAVE_SYS_SELECT_H \
    -DHAVE_UNISTD_H \
    -DHAVE_STRTOL \
    -DHAVE_LRAND48 \
    -DHAVE_TIME_H \
    -DHAVE_SYS_TIME_H \
    -DHAVE_STRUCT_TIMEVAL  -DEXOSIP___FLAGS \
    -DHAVE_NETINET_TCP_H \
    -DHAVE_ARPA_INET_H \
    -DHAVE_ARPA_NAMESER_H \
    -DHAVE_RESOLV_H \
    -DHAVE_NETDB_H \
    -DHAVE_STRING_H \
    -DHAVE_STRINGS_H \
    -DSRV_RECORD \
    -DHAVE_CARES_H \
    -DHAVE_OPENSSL_SSL_H

LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DENABLE_TRACE

旁注:上面还针对c-ares 库进行编译,这是 osip2/eXosip2 的一个有价值的依赖项。

sidenote2:上面的代码也可以针对 openssl 库进行编译……出于显而易见的原因,也很有价值。

如果您愿意,您可以删除 HAVE_CARES_H 和 HAVE_OPENSSL_SSL_H。

【讨论】:

    【解决方案6】:

    如果您无法将目标更改为 19,或者使用实验性 gradle 设置 NDK 目标,您仍然可以使用 boost 代替: Boost.Random

    用法与C++ 11类似。示例:

    #include <boost/random/mersenne_twister.hpp>
    #include "boost/random.hpp"
    
    int main() {
        boost::mt19937 randomGenerator.seed((unsigned int)time(0));
        boost::uniform_int<> uniform(1, 10);
        return uniform(_randomGenerator);
    }
    

    由于实现主要在 .hpp 文件中,因此很容易将其包含在您的代码中。

    【讨论】:

      【解决方案7】:

      在我的情况下,错误不是针对srand,而是针对不同的功能:__ctype_get_mb_cur_max ndk

      通过设置特定的 NDK 平台版本来修复它:

      APP_PLATFORM := android-15

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-19
        • 2014-11-30
        • 1970-01-01
        • 2021-05-18
        • 2019-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多