Android NDK: load_library: cannot locate srand
Asked Answered
N

7

14

I have an android project where I use native code to do stuff with SIP (using libosip2 and libeXosip2). My native code is compiled together with the libraries' sources into one module.

The code compiles just fine and the generated library has all the symbols I expect it to have, but when I try to load the generated library I get the following error:

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

My Application.mk looks like this:

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

I did check for uncaught dependencies using ndk-depends, which gives me

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

Adding a loadLibrary("gnustl_shared") does not help (which is the only one of the mentioned libraries also found in "libs/armeabi-v7/").

My 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++ is not my fortitude, so if someone could enlighten me I'd be really grateful :) As an alternative, a solution to my problem would also be nice ^^


Update 1

I separated the eXosip/osip library from my code, compiling it into a static library. I also tested creating a shared library and loading it by hand from inside Java, it fails with the same error message.

Update 2

I tried using gnustl_shared, static and also stlport - the error remains.

Neoprene answered 24/8, 2014 at 18:39 Comment(9)
grep your various .so's and find which one depends on srand. Add an implementation/emulation based on something Android does support, perhaps a different random AP.Casiecasilda
I still don't know what it was, so I'll leave this unanswered for a bit longer to see if someone can come up with a real solution. I now got it working downgrading my NDK from r10 to r9d. Not sure what is different, it seems like I'm the only one who experienced this.Neoprene
Two key questions: What exact NDK R10 download did you use? Next, do any lines in the output of find YOUR_NDK_R10_DIRECTORY -name "stdlib.h" | xargs grep "srand(" not specify "inline" ?Casiecasilda
Hi, @Managarm, do you remember the root cause for this? I'm struggling to figure out why this happens. In my case it's a different function which is part of libc. How the hell is missing?Iveson
@Iveson In my case this was because I was using the 64bit NDK. Using the 32bit NDK worked for me.Neoprene
Hm, I always though the host OS doesn't matter for the end result (if it's Mac, Windows or Linux and if it's 32 or 64 bit) as we always cross-compilation. But, yes, if it's a bug...! In my case the problem was the same as youts but for a different function called __ctype_get_mb_cur_max ndk. In turned out that after switching to a specific APP_PLATFORM := android-15 it disappeared! Almost a day of guesswork! P.s. Did you build sqlcipher?Iveson
@Iveson If I recall correctly the 32/64bit versions are what is used on the target device, the host OS shouldn't matter. If it works I would advise to use a newer target then 15 as it is quite outdated.Neoprene
Actually the native target is better to be as lower as possible - best to be aligned with the minSdkLevel in manifest. About the 32/64 - i don't know how it was in the past years but now the NDK contains both 32 and 64 toolchains no matter what host OS is. You can build 32-bit libs on 64-bit OS and vice versa.Iveson
@Iveson Interesting, I didn't know that. // I believe before r10c the NDK was separated into 32 and 64bit versions. Anyway, glad it works for you now :) Maybe you can add your solution as another answer. // By the way, I did not build sqlcipher. Sorry~Neoprene
N
2

Thanks to Chris I realized my mistake, which was using the NDK intended for 64bit devices. Though I could not replicate the error using a minimal example (it seems to be specific to libosip2 and possibly others), using the 32bit NDK resolved the issue.

Thank you everyone who took the time to comment and post suggestions!

Neoprene answered 29/8, 2014 at 10:54 Comment(3)
Can you give me the download link for NDK 32 r10b for mac ?Winterfeed
This worked then, but it probably not a viable path for the future as it means being tied to a dated NDK release. I suspect that Michaël's answer mentioning the role off the android target setting will be the more useful one as time goes on.Casiecasilda
The issue is not at all specific to libosip2. Any library using srand will fail with old Android target and not with newer. To use libosip2 with any Android target, see my answer and use -DHAVE_LRAND48Gamo
C
18

For those stumbling onto this thread while having trouble with srand/atof on NDK r10c: Make sure you set your android target to 19. Your app should then work on Android 5 (21) as well as all lower versions.

If you set your android target to 21, then your app will ONLY run on Android 5. Your app will however no longer work on all lower android versions, because a lot of stdlib functions cannot be found (like srand/atof).

Kind regards, Michaël

Clockwise answered 23/10, 2014 at 5:59 Comment(1)
On the contrary, this is very much an answer, and an important one.Casiecasilda
N
2

Thanks to Chris I realized my mistake, which was using the NDK intended for 64bit devices. Though I could not replicate the error using a minimal example (it seems to be specific to libosip2 and possibly others), using the 32bit NDK resolved the issue.

Thank you everyone who took the time to comment and post suggestions!

Neoprene answered 29/8, 2014 at 10:54 Comment(3)
Can you give me the download link for NDK 32 r10b for mac ?Winterfeed
This worked then, but it probably not a viable path for the future as it means being tied to a dated NDK release. I suspect that Michaël's answer mentioning the role off the android target setting will be the more useful one as time goes on.Casiecasilda
The issue is not at all specific to libosip2. Any library using srand will fail with old Android target and not with newer. To use libosip2 with any Android target, see my answer and use -DHAVE_LRAND48Gamo
E
2

The same problem happens also for int rand(void) and int rand_r(unsigned int*) functions on NDK64 r10b (September 2014).. To reproduce, just compile any of the samples provided with the NDK64 r10b, and make a call to int rand(void) or int rand_r(unsigned int*).

On NDK32 r10b these functions are defined in stdlib.h as static __inline__ , but not on NDK64 r10b.

Using NDK32 r10b, as mentioned by Managarm, solves the problem, but it is a blocking point for those who want to compile for the arm64-v8a target!

Came to the conclusion that NDK64 r10b has a bug on this particular point.

Possible patch: replace the original definitions of the missing functions, in the NDK64 r10b stdlib.h, by the static ones from the NDK32 r10b stdlib.h. Ex: for the srand(), it'd become:

static __inline__ void srand(unsigned int __s)
{
        srand48(__s);
}
Exercitation answered 1/10, 2014 at 22:56 Comment(1)
Can you give me the download link for NDK 32 r10b for mac ?Winterfeed
A
1

srand is defined as inline in

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

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

I cannot tell what your extarct_stuff.sh does, and I do not think that separating the static library (libraries) makes any difference. But somewhere you are using non-NDK headers (maybe your /usr/include, if you are on Linux. You can run ndk-build V=1 to see all actual commands that run the compiler, and check if some unexpected -I is used somewhere. Maybe, srand is defined in one of the files in $(LOCAL_PATH)/$(OSIP)/include or $(LOCAL_PATH)/$(EXOSIP)/include.

Airglow answered 25/8, 2014 at 18:26 Comment(1)
I checked and did not see anything out of the ordinary. I got it working for now downgrading the NDK from r10 to r9d. Thank your for your suggestion!Neoprene
G
0

On Android, osip2 should be compiled with -DHAVE_LRAND48. Then, osip2 won't use anymore srand. This will allow you to compile osip2 and eXosip2 with any target. lrand48 exists at least since android-3.

Here are the flags I use to compile osip2 and 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: The above also compiles against c-ares library which is a valuable dependancy for osip2/eXosip2.

sidenote2: The above also compiles against openssl library... also valuable for obvious reasons.

You may remove HAVE_CARES_H and HAVE_OPENSSL_SSL_H if you wish.

Gamo answered 1/10, 2015 at 16:19 Comment(0)
I
0

In my case the error was not for srand but for a different function: __ctype_get_mb_cur_max ndk.

Fixed it by setting a specific NDK platform version:

APP_PLATFORM := android-15

Iveson answered 1/7, 2016 at 14:4 Comment(0)
E
-1

If you are unable to change the target to 19, or use the experimental gradle to set the NDK target, you can still use boost instead: Boost.Random

The usage is similar to C++ 11. Example:

#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);
}

Since the implementation is mostly in .hpp files, it is pretty easy to include in your code.

Entitle answered 28/3, 2016 at 12:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.