NDK - Build ARMv5/ARMv7 shared libraries from static ones - android

I have two static libraries that I built from a specified project.
ARMv5 / myLib.a
ARMv7 / myLib.a
Now, I want to use those libraries and build two shared library for ARMv5 and ARMV7 platforms.
Is there a way to specify the fact that I want to use two versions of my static library ?
For now, I'm doing a bad trick in my ANT Script which just consists in:
Copy the static ARMv5 library.
Build the shared library (ARMv5).
Delete ARMv5 static lib and copy ARMv7 version.
Build again a shared library (ARMv7).
I know there is
"APP_ABI := armeabi armeabi-v7a"
but how to tell him that I want to build from two separated static lib and not just from one?
Regards,

Might not be the best approach but, you can try using if else statements in your Android.mk and check for APP_ABI values and use the corresponding libraries.
ifeq ($(APP_ABI), armeabi-v7a)
LOCAL_SRC_FILES := ARMv7/myLib.a
else
LOCAL_SRC_FILES := ARMv5/myLib.a
endif
Or use LOCAL_STATIC_LIBRARIES in case you directly link them. Of course, your Application.mk should include the line that you stated:
APP_ABI := armeabi armeabi-v7a

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).

Android NDK - Build Trying to Link Non-Existent Prebuilt Library

I just inherited some legacy code, which is currently able to build on our build server and I am trying to get it run on Android Studio, and it is having issue where the build fails because it is trying to point to a (non-existent) MIPS version of a prebuilt library.
I get the following error:
libraryname: LOCAL_SRC_FILES points to a missing file.
Check that .../libraryname/mips/libraryname.so exists.
This file does not exist, but I don't understand why the build tool is looking for it.
My Application.mk file has this entry:
APP_ABI := armeabi armeabi-v7a x86 x86_64
My Android.mk file has this entry (library name generalized):
include $(CLEAR_VARS)
LIBRARY_NAME_PATH := libraryname/$(TARGET_ARCH_ABI)
LOCAL_MODULE := modulename
LOCAL_SRC_FILES := $(LIBRARY_NAME_PATH)/mobulename.so
include $(PREBUILT_SHARED_LIBRARY)
Confusingly, TARGET_ARCH_ABI doesn't seem to be set anywhere, so I'm not really sure what is happening there.
Other notes, when I build this from the command line with NDK-build, it works just fine, only creating the 4 architectures requested.
As I mentioned, there should be no need for any code changes, since this exact code is successfully building on our build server. I am assuming I just have something configured wrong.
Traditionally, NDK used APP_ABIS setting (usually defined in Application.mk file) to choose the list of architectures to build. NDK supports today ARM, Intel and MIPS processors in 32 and 64-bit modes.
The gradle plugin used by Android Studio ignores APP_ABIS and you must define abiFilters in your build.gradle to specify the architectures to build.
This is especially important when your project uses prebuilt third-party libraries, because quite often, as in your case, these libraries are available only to a subset of all possible architectures.
ndk-build invokes the Android.mk script in a loop, each time setting $(TARGET_ARCH_ABI) to chosen architecture, one of arm64-v8a
x86_64
mips64
armeabi-v7a
armeabi
x86
mips

Android NDK: build fat binary with BUILD_EXECUTABLE and armeabi-v7a-hard

Short: How does Android NDK system transform "APP_ABI := armeabi-v7a-hard" to final .so files located in "libs/armeabi-v7a"? What is the proper way to do same thing in Android.mk? Currently, to build standalone executable and place it in folders corresponding to different ABIs I use this, which is it looks ugly because of hard coded "ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard)":
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
SAVED_NDK_APP_DST_DIR := $(NDK_APP_DST_DIR)
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard)
NDK_APP_DST_DIR := assets/armeabi-v7a
else
NDK_APP_DST_DIR := assets/$(TARGET_ARCH_ABI)
endif
LOCAL_MODULE := run_pie
LOCAL_SRC_FILES := run_pie.c
include $(BUILD_EXECUTABLE)
NDK_APP_DST_DIR := $(SAVED_NDK_APP_DST_DIR)
Long: In my Android app I'm using set of standalone binaries. After build they stored in APK resources. On first app launch I copy them to my app private folder, chmod 777, and than use them as system utilities, like "ls" or "cp". I want to produce "fat binary": single APK that has binaries for all ABIs and choose right binary for current device after installation. For .so libraries Android doing all this stuff automatically. And "APP_ABI := armeabi-v7a-hard" is internal to NDK build system, it's stated in docs, and final .so files for "armeabi-v7a-hard" is placed in "armeabi-v7a" folder. I can do same for my binaries and currently I have way that is working, however it looks ugly.
What is the proper way to place output binaries to custom folders named with ABIs and handle "armeabi-v7a-hard" to "armeabi-v7a" conversion?
If you look into $NDK/build/core/setup-toolchain.mk, you'll find the following lines there:
# compute NDK_APP_DST_DIR as the destination directory for the generated files
NDK_APP_DST_DIR := $(NDK_APP_LIBS_OUT)/$(TARGET_ARCH_ABI)
# install armeabi-v7a-hard to lib/armeabi-v7a, unless under testing where env. var. _NDK_TESTING_ALL_
# is set to one of yes, all, all32, or all64
ifeq (,$(filter yes all all32 all64,$(_NDK_TESTING_ALL_)))
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard)
NDK_APP_DST_DIR := $(NDK_APP_LIBS_OUT)/armeabi-v7a
endif
endif
So, as you see, it's the same approach as you do in your Android.mk. The only difference is that you don't take into account _NDK_TESTING_ALL_, which is internal to NDK testing system. So just continue use your Android.mk as is and don't worry.
Another approach would be to build your executables as usual, but name them as lib${TOOLNAME}.so. In this case they will be placed into default NDK_APP_DST_DIR as well as real libraries, and when installing on device, Android Package Manager will copy them into proper place. Then, on first run, you could copy them from lib folder (rather than from assets, as you do currently), and rename appropriately.

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.

Android different ABI compatibility

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

Categories

Resources