Objective Cross compile Cisco libsrtp for Android using NDK toolchain and use libsrtp.a to statically link against my own library.
Setup : I make use of the following file
<setup.sh>
export CROSS_SYSROOT=/home/psurana/aa/sysroot
export CROSS_COMPILE=aarch64-linux-android-
export SYSROOT=/home/psurana/aa/sysroot
export CC="${CROSS_COMPILE}gcc --sysroot=${SYSROOT}"
export CXX="${CROSS_COMPILE}gxx --sysroot=${SYSROOT}"
PATH=/home/psurana/aa/bin:$PATH
then I do the following configure:
source setup.sh && ./configure --host=aarch64-linux-android --build=`./config.guess` && make -j
This compiles it for me. doing a readelf -h libsrtp.a, yields--
File: libsrtp.a(ut_sim.o)
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: AArch64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 1480 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 10
Section header string table index: 7
So far so good.
Problem
However, when I link libsrtp.a as a prebuilt static library, I get following errors:
./srtp/libsrtp.a(rand_source.o): In function `rand_source_init':
err.c:(.text+0x0): undefined reference to `stdout'
err.c:(.text+0xc): undefined reference to `stdout'
and,
rand_source.c:(.text+0x28): undefined reference to `stderr'
rand_source.c:(.text+0x3c): undefined reference to `stderr'
My understanding is that Android does not have stderr in its libc, but then how does libsrtp get these?
I have previously built the same library using something similar and I know it builds. I do not know what the error might be.
I usually get this undefined reference with libc in any platform after 21 so I usually add -D__ANDROID_API__=21 to CFLAGS and it ends up fixing it. I believe the issue comes from the new unified headers in newer ndk versions.
Related
I'm submitting an apk to goole play that seems perfectly 64 bits compliant, it has all native libraries provided in 32 bits and 64 bits. But I still get this error when trying to deploy the apk in the gogole play console :
This release is not compliant with the Google Play 64-bit requirement
The following APKs or App Bundles are available to 64-bit devices,
but they only have 32-bit native code: 2.
Include 64-bit and 32-bit native code in your app. Use the Android
App Bundle publishing format to automatically ensure that each device
architecture receives only the native code that it needs. This
avoids increasing the overall size of your app. Learn More
Here is a screenshot of native libraries in the apk :
This apk seems to be perfectly 64 bits compliant to me, I'm really stuck on this, any help or idea very appreciated.
[edit 2019 11 14] After comment from following comment from Robert, I checked all 10 .so libraries with the tool arm-linux-androideabi-readelf provided by the ndk.
I used these 2 commands :
arm-linux-androideabi-readelf -h armeabi-v7a/*
which outputs 10 ELF headers looking like this :
File: armeabi-v7a/libVuforia.so
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 52 (bytes into file)
Start of section headers: 17252004 (bytes into file)
Flags: 0x5000200, Version5 EABI, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 27
And :
arm-linux-androideabi-readelf -h arm64-v8a/*
which outputs 10 ELF headers looking like this :
File: arm64-v8a/libVuforia.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: AArch64
Version: 0x1
Entry point address: 0x10f3a0
Start of program headers: 64 (bytes into file)
Start of section headers: 27138992 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 26
Section header string table index: 25
That seems to confirm that the 10 .so libraries are correctly provided in 32 and 64 bits. Still stuck, any help very appreciated.
I found a solution (for my case - maybe the same as yours)
In the Dev console, I had an old apk which was set as "retained" (in 32bits, for old Android devices : 14+ to 19).
Disabling it allowed me to successfully deploy my new bundle.
Hope it can help.
I'm using shared object libraries in Android application. These shared object libraries are in .aar file.
One of library is crashing. In order to check crash logs and exact line no. I am using ndk-stack took.
Usage of ndk-stack is
$ adb logcat | ndk-stack -sym <Path to your shared libraries>
Now How can I get a path of shared libraries in AAR file?
You should keep in mind that not every .so file is useful for ndk-stack. Android NDK produces two kinds of .so files: stripped and non-stripped. The most difference is that last ones contain debug information, that is needed for ndk-stack and first ones don't. readelf may help to check if particular file is stripped or not:
$ readelf <non-stripped-lib> -S | grep debug
[23] .debug_info PROGBITS 00000000 00302c 0052d9 00 0 0 1
[24] .debug_abbrev PROGBITS 00000000 008305 000879 00 0 0 1
[25] .debug_loc PROGBITS 00000000 008b7e 001aa7 00 0 0 1
[26] .debug_aranges PROGBITS 00000000 00a628 000088 00 0 0 8
[27] .debug_ranges PROGBITS 00000000 00a6b0 0000d0 00 0 0 1
[28] .debug_line PROGBITS 00000000 00a780 0009de 00 0 0 1
[29] .debug_str PROGBITS 00000000 00b15e 002387 01 MS 0 0 1
[30] .debug_frame PROGBITS 00000000 00d4e8 0003d0 00 0 0 4
$
$ readelf <stripped-lib> -S | grep debug
$
As you see not-stripped ELF has a lot of .debug_* sections, that indeed contain line numbers, private / static function names, etc.
Next, .aar files, both debug and release ones, has only stripped binaries. So they are useless for ndk-stack.
AFAIK, the only place where non-stripped binaries may be found is a obj/ dir. Its location depends slightly on used build system:
for ndk-build it is under <module_name>/build/intermediates/ndk
for CMake-based it is under <module_name>/build/intermediates/cmake
Also it looks like out-of-the-box android gradle plugin offers no way to pack unstripped libraries to your aar, so the only way here is some custom task in your build.gradle.
I have built openssl for 5/7 of the android-21 (android-L) architectures: armeabi, armeabi-v7a, arm64, mips, x86. However I am unable to build it for x86_64 and mips64.
What I'm doing...
x86 - working
The following is my working script for x86, using a toolchain created by make-standalone-toolchain:
export ANDROID_NDK_ROOT=/Users/jacsteve/dev/android/ndk
export ANDROID_API=android-21
export ANDROID_ARCH=arch-x86
export ANDROID_EABI=i686-linux-android-4.9
export ANDROID_SYSROOT=$ANDROID_NDK_ROOT/platforms/$ANDROID_API/arch-x86
export ANDROID_TOOLCHAIN=/tmp/toolchain/x86
export ANDROID_DEV=$ANDROID_SYSROOT/usr
export SYSTEM=android
export ARCH=x86
export CROSS_COMPILE=i686-linux-android-
export CFLAGS="--sysroot=$ANDROID_SYSROOT"
export CPPFLAGS="--sysroot=$ANDROID_SYSROOT"
export CXXFLAGS="--sysroot=$ANDROID_SYSROOT"
./Configure android-x86 shared no-asm -no-ssl2 -no-ssl3 -no-comp -no-hw --cross-compile-prefix=$CROSS_COMPILE --openssldir=/tmp/ssl/x86
make depend
make
make install
This works fine, and leaves me with libssl.so and libcrypto.so in /tmp/ssl/x86
x86_64 - fails
However, x86_64 fails. Here's the script:
export ANDROID_NDK_ROOT=/Users/jacsteve/dev/android/ndk
export ANDROID_API=android-21
export ANDROID_ARCH=arch-x86_64
export ANDROID_EABI=x86_64-linux-android-4.9
export ANDROID_SYSROOT=$ANDROID_NDK_ROOT/platforms/$ANDROID_API/arch-x86_64
export ANDROID_TOOLCHAIN=/tmp/toolchain/x86_64
export ANDROID_DEV=$ANDROID_SYSROOT/usr
export SYSTEM=android
export ARCH=x86_64
export CROSS_COMPILE=x86_64-linux-android-
export CFLAGS="--sysroot=$ANDROID_SYSROOT"
export CPPFLAGS="--sysroot=$ANDROID_SYSROOT"
export CXXFLAGS="--sysroot=$ANDROID_SYSROOT"
./Configure android-x86 shared no-asm -m64 -no-ssl2 -no-ssl3 -no-comp -no-hw --cross-compile-prefix=$CROSS_COMPILE --openssldir=/tmp/ssl/x86_64
make depend
make
make install
The Errors...
x86_64
I get a load of error messages from the make call that look like this:
/private/tmp/toolchain/x86_64/bin/../lib/gcc/x86_64-linux-android/4.9/../../../../x86_64-linux-android/bin/ld:
error: libcrypto.a(cryptlib.o): incompatible target
/private/tmp/toolchain/x86_64/bin/../lib/gcc/x86_64-linux-android/4.9/../../../../x86_64-linux-android/bin/ld:
error: libcrypto.a(mem.o): incompatible target
...
collect2: error: ld returned 1 exit status
It looks to me like x86_64-linux-android-gcc is compiling everything fine, but when we get to the linking stage, x86_64-linux-android-ld can't read the compiled object files.
mips64
Using a similar setup for mips64 (with ./Configure android-mips ...) I get the following error, which looks to be a similar issue to do with mips64-linux-android-ld being unable to read object files:
/Users/jacsteve/dev/android/ndk/platforms/android-21/arch-mips64/usr/lib/libdl.so: error adding symbols: File in wrong format
collect2: error: ld returned 1 exit status
Does anyone know how to build the x86_64 and mips64 architectures successfully?
Solved!
Instead of
./Configure android-x86 ...
I used
./Configure linux-generic64 ...
I also used linux-generic32 for the 32bit architectures.
Running make clean before ./Configure solved the problem for me.
The error from building openssl for mips64, I guess, resulted from the incompatible ABI format between objects and libraries, which the format objects is mips-ELF64, while libraries provided by ANDROID_NDK is mips ELF32
cd ${ANDROID_NDK_HOME}/platforms/android-24/arch-mips64/usr/lib
readelf -h libc.so
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0xa7d0
Start of program headers: 52 (bytes into file)
Start of section headers: 204792 (bytes into file)
Flags: 0x50001007, noreorder, pic, cpic, o32, mips32
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 18
Section header string table index: 15
I am still getting warning requires library libhoudini by logcat, also i have compiled all library into arch x86.
On the Emulator without support Binary Translator - Log:
04-14 18:05:05.304: D/FFMpeg(992): ### Try to load lib: jniaudio
04-14 18:05:05.304: D/dalvikvm(992): Trying to load lib /data/data/com.app.test/lib/libjniaudio.so 0xa6a0d230
04-14 18:05:05.304: D/FFMpeg(992): Couldn't load lib: jniaudio - Cannot load library: load_library[1093]: Library '/system/lib/libhoudini.so' not found
On the Emulator with installed support Binary Translator - Log:
04-14 18:05:05.304: D/FFMpeg(992): ### Try to load lib: jniaudio
04-14 19:34:00.764: D/dalvikvm(1171): Trying to load lib /data/data/com.app.test/lib/libjniaudio.so 0xa68cbd98
04-14 19:34:00.804: E/dalvikvm(1171): The lib may be ARM... trying to load it [/data/data/com.app.test/lib/libjniaudio.so] using houdini
04-14 19:34:00.808: D/houdini(1171): [1171] Loading library(version: 2.0.5.42475 RELEASE)... successfully.
04-14 19:34:00.808: E/dalvikvm(1171): dvm_dlopen: unable to open /data/data/com.app.test/lib/libjniaudio.so
Application.mk
APP_ABI := x86
APP_PLATFORM := android-14
I can't load native libraries on my emulator, but system makes wrong for determining the target architecture of shared library. I'd be grateful if someone could explain.?
UPDATE 1.
/obj/local/x86/libjniaudio.so - here header information of shared library.
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 52 (bytes into file)
Start of section headers: 68664 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 32
Section header string table index: 31
are you 100% sure your library is an x86 binary ?
The binary translator shouldn't load up in this case.
You can check the real ABI of your files using readelf, file, or this Android app I've made: https://play.google.com/store/apps/details?id=com.xh.nativelibsmonitor.app (x86 only for now)
I'm trying to build a dynamic library for android wrapper around libcrypto.a as described in
http://wiki.openssl.org/index.php/FIPS_Library_and_Android#Using_FIPS_OpenSSL_in_a_real_Application
I've produced the libcrypto.a as suggested on the page, but when I try to compile my wrapper.c I get a linker error, multiple definition of 'atexit'
Here's the command line I'm using to compile:
arm-linux-androideabi-gcc wrapper.c -fPIC -shared -I/usr/local/ssl/android-14/include -Wl,-Bstatic -lcrypto -L/usr/local/ssl/android-14/lib -o libwrapper.so --sysroot=/Users/scoleman/android-ndk-r9d/platforms/android-14/arch-arm -Wl, -Bdynamic
Here are the results:
/Users/scoleman/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: /Users/scoleman/android-ndk-r9d/platforms/android-14/arch-arm/usr/lib/libc.a(atexit.o): multiple definition of 'atexit'
/Users/scoleman/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /Users/scoleman/android-ndk-r9d/platforms/android-14/arch-arm/usr/lib/crtbegin_so.o: previous definition here
/Users/scoleman/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: cannot find -ldl
collect2: ld returned 1 exit status
Here's my wrapper.c:
#include <string.h>
#include <jni.h>
int MY_FIPS_mode() {
int mode = mode = FIPS_mode();
return mode;
}
Here's the command line I'm using to compile:
arm-linux-androideabi-gcc wrapper.c -fPIC -shared -I/usr/local/ssl/android-14/include -Wl,-Bstatic -lcrypto -L/usr/local/ssl/android-14/lib -o libwrapper.so --sysroot=/Users/scoleman/android-ndk-r9d/platforms/android-14/arch-arm -Wl, -Bdynamic
I was able to duplicate the issue with your command line. The way I would approach this is (line breaks added for readability):
arm-linux-androideabi-gcc wrapper.c -fPIC -shared -o libwrapper.so
--sysroot=.../android-ndk-r9d/platforms/android-14/arch-arm
-I/usr/local/ssl/android-14/include
/usr/local/ssl/android-14/lib/libssl.a
/usr/local/ssl/android-14/lib/libcrypto.a
-ldl
--sysroot will bring in the platform headers and libraries for Android 4.0 (API 14). That should be where atexit is defined. I think the -Bstatic and -Bdynamic might be complicating things since atexit was provided by both libc.a and crtbegin_so.o.
I avoid -Bstatic and -Bdynamic. When I want static linking, I specifically call out the full pathname of the static library, like /usr/local/ssl/android-14/lib/libcrypto.a. Remember, an archive is a collection of object files (*.o), so you can use it wherever you can use an object file.
Using the setenv-android.sh script from the page and your source, I was not able to duplicate:
$ . ./setenv-android.sh
ANDROID_NDK_ROOT: /opt/android-ndk-r9
ANDROID_EABI: arm-linux-androideabi-4.6
ANDROID_API: android-14
ANDROID_SYSROOT: /opt/android-ndk-r9/platforms/android-14/arch-arm
ANDROID_TOOLCHAIN: /opt/android-ndk-r9/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin
CROSS_COMPILE: arm-linux-androideabi-
ANDROID_DEV: /opt/android-ndk-r9/platforms/android-14/arch-arm/usr
$ cat wrapper.c
#include <string.h>
#include <jni.h>
#include <openssl/evp.h>
int MY_FIPS_mode() {
int mode = FIPS_mode();
return mode;
}
$ arm-linux-androideabi-gcc wrapper.c -fPIC -shared -o libwrapper.so \
> --sysroot=$ANDROID_SYSROOT \
> -I/usr/local/ssl/android-14/include \
> /usr/local/ssl/android-14/lib/libssl.a \
> /usr/local/ssl/android-14/lib/libcrypto.a \
> -ldl
$ ls
libwrapper.so setenv-android.sh wrapper.c
$ arm-linux-androideabi-readelf -h libwrapper.so
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 52 (bytes into file)
Start of section headers: 244660 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 34
Section header string table index: 33
$ arm-linux-androideabi-nm -D libwrapper.so | grep MY_FIPS_mode
00009fa4 T MY_FIPS_mode