Подтвердить что ты не робот

Android NDK: load_library: не удается найти srand

У меня есть проект Android, где я использую собственный код для работы с SIP (используя libosip2 и libeXosip2). Мой собственный код скомпилирован вместе с источниками библиотек в один модуль.

Код компилируется просто отлично, и у сгенерированной библиотеки есть все символы, которые я ожидаю, но когда я пытаюсь загрузить сгенерированную библиотеку, я получаю следующую ошибку:

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

My Application.mk выглядит так:

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

Я проверял наличие неперехваченных зависимостей, используя ndk-depend, что дает мне

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/С++ - это не моя стойкость, поэтому, если кто-то может просветить меня, я был бы очень благодарен:) В качестве альтернативы решение моей проблемы было бы также приятным ^^


Обновление 1

Я отделил библиотеку eXosip/osip от своего кода, скомпилировав его в статической библиотеке. Я также протестировал создание общей библиотеки и загрузку ее вручную изнутри Java, она не работает с тем же сообщением об ошибке.

Обновление 2

Я попытался использовать gnustl_shared, static, а также stlport - ошибка остается.

4b9b3361

Ответ 1

Благодаря Крису я осознал свою ошибку, которая использовала NDK для 64-битных устройств. Хотя я не смог реплицировать ошибку, используя минимальный пример (он, по-видимому, специфичен для libosip2 и, возможно, для других), с использованием 32-разрядного NDK разрешил проблему.

Спасибо всем, кто нашел время, чтобы прокомментировать и опубликовать предложения!

Ответ 2

Для тех, кто наткнулся на эту тему, столкнувшись с проблемой srand/atof на NDK r10c: убедитесь, что вы настроили целевой Android на 19. Затем ваше приложение должно работать на Android 5 (21), а также на все более низкие версии.

Если вы установите для своей целевой Android значение 21, ваше приложение будет ТОЛЬКО запускаться на Android 5. Однако ваше приложение больше не будет работать на всех более низких версиях Android, так как многие функции stdlib не могут быть найдены (например, srand/atof).

С уважением, Микаэль

Ответ 3

Аналогичная проблема возникает и для функций int rand(void) и int rand_r(unsigned int*) на NDK64 r10b (сентябрь 2014 г.). Чтобы воспроизвести, просто скомпилируйте любой из образцов, поставляемых с NDK64 r10b, и сделайте вызов int rand(void) или int rand_r(unsigned int*).

В NDK32 r10b эти функции определены в stdlib.h как static __inline__, но не на NDK64 r10b.

Использование NDK32 r10b, как упоминалось в Managarm, решает проблему, но это точка блокировки для тех, кто хочет скомпилировать для цели arm64-v8a!

Пришел к выводу, что NDK64 r10b имеет ошибку в этой конкретной точке.

Возможный патч: замените исходные определения отсутствующих функций в NDK64 r10b stdlib.h на static из NDK32 r10b stdlib.h. Пример: для srand() он стал бы следующим:

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

Ответ 4

srand определяется как встроенный в

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

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

Я не могу сказать, что делает ваш extarct_stuff.sh, и я не думаю, что разделение статической библиотеки (библиотек) имеет значение. Но где-то вы используете заголовки, отличные от NDK (возможно, ваш /usr/include, если вы находитесь в Linux. Вы можете запустить ndk-build V=1, чтобы увидеть все фактические команды, запускающие компилятор, и проверить, где-то используется некоторая неожиданная -I. Возможно, srand определяется в одном из файлов в $(LOCAL_PATH)/$(OSIP)/include или $(LOCAL_PATH)/$(EXOSIP)/include.

Ответ 5

В Android, osip2 должен быть скомпилирован с -DHAVE_LRAND48. Затем osip2 больше не будет использовать srand. Это позволит вам скомпилировать osip2 и eXosip2 с любой целью. lrand48 существует по крайней мере с момента андроида-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

sidenote: выше также компилируется библиотека c-ares, которая является ценной зависимостью для osip2/eXosip2.

sidenote2: вышеприведенное также компилируется против библиотеки openssl... также полезно по очевидным причинам.

Вы можете удалить HAVE_CARES_H и HAVE_OPENSSL_SSL_H, если хотите.

Ответ 6

В моем случае ошибка была не для srand, а для другой функции: __ctype_get_mb_cur_max ndk.

Исправлено, установив определенную версию платформы NDK:

APP_PLATFORM := android-15

Ответ 7

Если вы не можете изменить цель на 19 или использовать экспериментальный gradle, чтобы установить цель NDK, вы все равно можете использовать boost: Boost.Random

Использование похоже на С++ 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, ее довольно легко включить в ваш код.