Android different ABI compatibility - android

For example let build static library called "some".
LibSome Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := some
LOCAL_SRC_FILES := some.c
include $(BUILD_STATIC_LIBRARY)
LibSome Application.mk
APP_MODULES := somelib
APP_OPTIM := release
And get armeabi version of our lib in LibSome/obj/local/armeabi/libsome.a
So now we need to drop our lib to mainProject jni folder and use it
MainProject Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := some
LOCAL_SRC_FILES := libsome.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/some
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := mainProject
LOCAL_SRC_FILES := mainProject.c
LOCAL_STATIC_LIBRARIES := some
include $(BUILD_SHARED_LIBRARY)
But there are different ABI like mips, x86, armeabi-v7a and we can get all supported versions of somelib by current ndk just adding
APP_ABI:= all
to SomeLib Application.mk, so we get LibSome/obj/local/armeabi-v7a/libsome.a, LibSome/obj/local/x86/libsome.a etc
Main question - do i really need to think about different ABI and create project for every supported ABI like mainProjectx86, mainProjectMIPS with different ABI builded libs?
And secondary questions are:
If i build project for armeabi ABI (default) how many devices will be cut out? Can armeabi-v7a ABI device run armeabi ABI app?
If there is a way to have one project with different set of pre-builded libs? So if you build mainProject for ameabi-v7a it will use armeabi-v7a libs and so on?

Ok, So firstly, if your are using standard C calls without any architecture specific assembly language embedded, it's safe to use APP_ABI := all. This will allow gcc to create libs for all architectures and your app will have no problems running.
if however, you are using something specific to ARM, e.g. NEON architecture calls for optimized math or Intel x86 SSE3 calls for optimized math, then APP_ABI := all may not be a good idea. This might lead to runtime errors which are very difficult to understand. Then you may be required to maintain different projects for different architectures.
Coming to secondary question:
1. Most of the latest devices are armeabi-v7a, so only the older devices will be cut out. Also parallel x86 and MIPS devices will also be cut out. But since most flagships like Samsung, HTC and Sony ship with ARM, your app will be reachable to a big percentage.
Not much clue on the second one for now.

All ARM devices run armeabi. The older and slower ones use ARMv6, and cannot use armeabi-v7a libraries. But it is possible to mix armeabi and ameabi-v7a shared libraries in one application. This may come useful if you have a huge native library which you don't want to ship in two copies, and also some very specific function that is a performance bottleneck which may be vastly accelerated with NEON optimizations. So, in the end you have the following structure in your project folder:
libs/
armeabi/
libhuge.so
libslow.so
armeabi-v7a/
libfast.so

Related

Android NDK - armeabi vs armeabi-v7a folder

There are some questions like mine.
why I need put *.so files in both armeabi-v7a and armeabi folders?
Why armeabi-v7a conflicts with armeabi of another module?
Why use armeabi-v7a code over armeabi code?
But I am not clear yet. I have many .so files for armeabi and armeabi-v7a.
// binaries
armeabi/libarmeabi-v7a-module1.so
armeabi/libarmeabi-v7a-module2.so
// Application.mk file
APP_ABI := armeabi
APP_PLATFORM := android-19
APP_STL := gnustl_shared
// Android.mk file
include $(CLEAR_VARS)
LOCAL_MODULE := module1
LOCAL_SRC_FILES := $(LOCAL_PATH)/armeabi/libarmeabi-v7a-module1.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := module2
LOCAL_SRC_FILES := $(LOCAL_PATH)/armeabi/libarmeabi-v7a-module2.so
include $(PREBUILT_SHARED_LIBRARY)
This settings work fine on armeabi-v7a devices.
But my app crashes when I set armeabi-v7a abi in Application.mk file. Crash message is below:
A/libc:
/Volumes/Android/buildbot/src/android/ndk-release-r16/external/libcxx/../../external/libcxxabi/src/abort_message.cpp:73:
abort_message: assertion "Pure virtual function called!" failed
armeabi is for up to ARM architecture version V6, while armeabi-v7a specifies architecture version version 7, with the suffix A for application processors such as Cortex-A15.
V7 has quite different pipleline behavior plus handful of nice and compiler friendly instructions compare to V6, such as ubfx.
e.g.:
a = (b>>5) & 0x3ff;
// armv6:
lsl a, b, #17
lsr a, a, #22
// armv7:
ubfx a, b, #5, #10 // unsigned bit-field extract from bit 5, ten bits long
As you can see above, you need two instructions with dependency on V6, while V7 only requires one single instruction which is remarkable considering how compiler friendly these new instructions are unlike the DSP-like ones new on V6 which mostly never got utilized by compilers.
And since the compiler has to decide which instructions to use and how to schedule them, the generated machine codes are different, so are the .so files, so are the folders.
I'd exclude armeabi altogether by abiFilters since there are virtually no Android phone with less than V7.
armeabi is armv5. It's no longer supported. You can just pretend it doesn't exist.
armeabi-v7a is armv7. This (along with at least arm64-v8a) is what you should be building for.
The fact that your app is crashing is a different problem, and the error message tells you what's happening: there's a pure virtual function that's being called. Some child class isn't implementing a virtual function that it needs to implement.
There's also a third problem. Your APP_STL is gnustl_shared, but the error message indicates that one of your libraries was built with libc++. These two are incompatible. You must use the same STL for the entire app (and since you use more than one shared library, it must be the shared variant).

Compile Intel TBB for Android - ARMv7 ARMv8 MIPS

I've found some serious difficulties in getting a working .so library to develop an Android app with Android NDK and intel TBB.
Basically I've downoaded version 4.4 Update 4 bundle for Android and followed the steps there (kind of, since the docs are not correct...).
Problem is that I can only get x86 and x86_64 .so libraries when compiling, since there are no armeabi-XXX or mips folders with the necessary .so in there.
Using the suggested command ./ndk-build.cmd tbb target=android arch=arm does not produce anything, in fact it tells me
/workspace/tbb44_20160413oss/lib/android/mips/libtbb.so library not found. Copy mips version of library to /home/filippo/workspace/tbb44_20160413oss/lib/android/mips folder to enable its build.
and the same for the other missing directories.
Threfore using only ./ndk-build.cmd tbb target=android gives me a cuople of dirs: x86 and x86_64 which I can use in Android Studio, and work with the emulator.
The result is taht I can properly test my apps on an emulator but cannot make it work into my personal device.
What am I missing here?
Application.mk
APP_ABI := x86 x86_64 // if I choose all, of course it won't find the .so for the other architectures
APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti
APP_STL := gnustl_shared
Android.mk
LOCAL_PATH := $(call my-dir)
#
# TBB
#
include $(CLEAR_VARS)
LOCAL_MODULE := libtbb
LOCAL_SRC_FILES := $(LOCAL_PATH)/$(TARGET_ARCH_ABI)/libtbb.so
include $(PREBUILT_SHARED_LIBRARY)
#
# Main module
#
include $(CLEAR_VARS)
LOCAL_MODULE := myndkapp
LOCAL_SHARED_LIBRARY := libtbb
include $(BUILD_SHARED_LIBRARY)
Thanks.
As you can see in 'jni/Application.mk' you can use targets 'ia32', 'intel64', 'arm' and 'arm64'.
Also it looks like you trying to build on Windows platform, so you should add a tbb_os=windows to your make command like this:
C:\TEMP\tbb44_20160413oss\src>ndk-build.cmd tbb tbbmalloc target=android arch=arm tbb_os=windows

How to build libvpx for android arm as well as x86?

I have been building our Android app for armeabi-v7a. Now, to add support for x86 as well, I extended Application.mk:
APP_ABI := armeabi-v7a x86
The first problem I am running into is that libvpx can be configured either for arm or for x86:
$ ./libvpx/configure --target=armv7-android-gcc ...
OR
$ ./libvpx/configure --target=x86-android-gcc
Wondering how to deal with multiple platforms. Does one create two different libvpx directories for two platforms and use if-then-else logic in Android.mk to pick the right directory? Is there a better way?
Yes, pretty much. If you store the build product (as produced by make install) in parallel directories named according to the android ABIs, you can simplify using it from an Android.mk file like this:
include $(CLEAR_VARS)
LOCAL_MODULE := libvpx
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libvpx/$(TARGET_ARCH_ABI)/include
LOCAL_SRC_FILES := libvpx/$(TARGET_ARCH_ABI)/lib/libvpx.a
include $(PREBUILT_STATIC_LIBRARY)
Since the public headers probably are (should be) free of anything arch specific, you should also be able to share one copy of them instead of having one copy per arch.

How to build multiple projects in the correct dependency order with Android NDK?

I have a series of existing libraries which I need to re-use in an Android application. The layout is similar to:
\Libraries\libOne
\Libraries\libTwo [Static library]
\Libraries\libThree
\Applications\MyApplication\ [Application]
libTwo depends on libOne, and libThree depends on libTwo. How can I get the build system to build all of the libraries in the correct order? I'm trying to use Eclipse, but if necessary I can use the command line.
All of these libraries will eventually be referenced by a Java application (and use JNI to interact with them). Any clues on how I setup the Android.mk / Application.mk files?
I've tried using BUILD_STATIC_LIBRARY for libTwo, but it doesn't actually output any files! I was expecting a libTwo.a file, but nothing gets compiled or built.
Do I write one Android.mk in the application? Or an Android.mk for each project?
OK, now I see your edit, and this makes it possible to answer the specific question.
You must have at least one Android.mk file for your application if you want to use Android NDK to build your native library/ies. This is not a requirement, though. It is OK to build it though Cmake, or a "standalone toolchain" with "traditional" makefiles, or with a MS Visual Studio plugin, or any other way. It is the result that matters. The result is a shared object built with a compatible compiler for a bionic runtime.
It makes goode sense to put the library in ${project_root}/libs/armeabi/ directory (for ARM v6 compatible devices, other subdirectories for x86, MIPS, arm v7a) to allow the APK builder pack it correctly, to allow app installer to unpack the correct version (compatible with the device processor) into /data/data/${package_name}/lib directory on the device, and finally to be able to use System.loadLibrary(short_name) to use it from Java. But it is also quite possible to pack the so file differently, unpack it manually, and load it from any place on the device file system (provided your app has permission to write and read this file).
But if we filter out exotic cases, it is much more comfortable to have an Android.mk in the ${project_root}/jni directory. In terms of ndk-build command, each library is a separate MODULE, but all three may be defined in one Android.mk file. On the other hand, if your libraries are isolated (e.g. come from separate 3rd parties), you will probably prefer to create three Android.mk files. Luckily, ndk-build is nothing but a wrapper around gnu make, and the simple include statement in Android.mk works as in any other makefiles.
In summary, your case is probably covered by a simple Applications/MyApplication/ [Application]/jni/Android.mk file:
include ../../Libraries/libOne/Android.mk
include ../../Libraries/libTwo/Android.mk
include ../../Libraries/libThree/Android.mk
I don't know what dependency you have between libOne and libTwo, but for libOne the file Libraries/libOne/Android.mk will look like
LOCAL_PATH = $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libOne
LOCAL_SRC_FILES := first.c
include $(BUILD_STATIC_LIBRARY)
and Libraries/libThree/Android.mk
LOCAL_PATH = $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libThree
LOCAL_SRC_FILES := third.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../libOne $(LOCAL_PATH)/../libTwo
LOCAL_STATIC_LIBRARIES := libOne libTwo
include $(BUILD_SHARED_LIBRARY)
You should run ndk-build from Applications/MyApplication/ [Application] directory - either from command prompt, or through Eclipse ADT plugin.
update the same may be expressed by one Android.mk file in jni directory:
LOCAL_PATH = ../../Libraries/libOne
include $(CLEAR_VARS)
LOCAL_MODULE := libOne
LOCAL_SRC_FILES := first.c
include $(BUILD_STATIC_LIBRARY)
LOCAL_PATH = ../../Libraries/libThree
include $(CLEAR_VARS)
LOCAL_MODULE := libThree
LOCAL_SRC_FILES := third.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../libOne $(LOCAL_PATH)/../libTwo
LOCAL_STATIC_LIBRARIES := libOne libTwo
include $(BUILD_SHARED_LIBRARY)
There is an android section in the projects' properties, where you can edit the library dependencies. It can only be used, if libOne libTwo and libThree are marked as libraries, in their properties panel.

How to force Android build script to place native libraries into the correct library folders according its eabi version?

I have an application which uses native libraries for various targets – ARMv6, ARMv6+vfp, ARM7+vfp, ARM7+Neon, ARM7 + Tegra as well as some universal libraries. My goal is to pack all the libraries into one .apk file so that I don’t have to distribute separate builds – I don’t care a much about the total .apk size.
Here is my Android.mk script – just an example but with enough info:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_ARCH_ABI := armeabi
LOCAL_MODULE := prebuilt_arm_v6vfp
LOCAL_SRC_FILES := ../bin/libplayer_v6vfp.so
LOCAL_EXPORT_LDLIBS := ../libplayer_v6vfp.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
TARGET_ARCH_ABI := armeabi-v7a
LOCAL_MODULE := prebuilt_arm_v7n
LOCAL_SRC_FILES := ../bin/libplayer_v7n.so
LOCAL_EXPORT_LDLIBS := ../libplayer_v7n.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := player
LOCAL_SRC_FILES := some_cpp_sources...
LOCAL_LDFLAGS := -L$(LOCAL_PATH)/../bin
LOCAL_LDLIBS := -llog -lz -lm -lplayer_v7n -lplayer_v6vfp
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
include $(BUILD_SHARED_LIBRARY)
Now I have the following problem – it creates libs folder with armeabi and armeabi-v7a subfolders – that’s OK. But the content of both subfolders is the same, both contains libplayer_v7n.so and libplayer_v6vfp.so as well.
How can I assure each subfolder contains only a correct version of native library according to its eabi version?
EDIT 1:
As you can see, I link libplayer.so with both shared libraries, they have compatible interfaces. I wanted to select the correct library dynamically when loading in my Java wrapper after detecting the CPU type. But it seems it is not possible. Any idea how to choose the correct library dynamically? There must be a solution for such a common case.
EDIT 2:
It seems I can link my libplayer.so only with one library and have to select its correct version at runtime. But now the problem is how to store six native libraries of various versions but with the same name in the lib folder. Subfolders seem to be an obvious solution, but I am not sure it is possible. The other solution would be to deploy the correct library via the separate .apk as a plug-in, but that’s exactly I want to avoid..
Then do the following:
name architecture specific libraries with same name (for example: libplayer_arch.so) & put them in different directories.
link libplayer.so to libplayer_arch.so
write your Java code like this:
.
if (isArmv7())
{
System.loadLibrary("armv7/libplayer_arch.so");
}
else
{
System.loadLibrary("armv6/libplayer_arch.so");
}
System.loadLibrary("libplayer.so");

Categories

Resources