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

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.

Related

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.

Shared library and Android NDK

I recently started to use Android NDK and I’m facing some problems with shared libraries.
I created a project with Eclipse that allows me to use NDK and natives functions. But now, I would like to use another shared library that I created with QtCreator.
So here is my question. Is that possible to include a shared library to my NDK project, even if I didn’t invoke ndk-build to create it?
Let’s take an example. If I create a simple shared library like that:
g++ -Wall -shared -fPIC -o libapi.so MyDLL.cpp
Could I be able to use it on my NDK project like this (Android.mk):
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := api
LOCAL_SRC_FILES := ../sharedLibs/libapi.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := dbapi
LOCAL_SRC_FILES := dbapi.cpp
LOCAL_C_INCLUDES += ../includes
LOCAL_SHARED_LIBRARIES := api
include $(BUILD_SHARED_LIBRARY)
And of course, could I be able to use its functions on my native NDK side?
Using this method, I'm facing this error when I try to build my Eclipse project:
/libs/armeabi-v7a/libapi.so: File format not recognized
I thought my shared lib was not compatible with ndk-build (true, false?).
Thank you for your answers.
How did you build your shared lib? Is it compiled for arm, with NDK?
If not, it cannot work.
The people in the comments are indicating that you have almost certainly compiled for x86 instead of arm. (You say you are using cygwin with Windows, which will compile to x86 by default unless your windows box is an arm box, which I am guessing is not the case.)
Inside the Android ndk is a script called make-standalone-toolchain.sh. If you are in the current directory where your ndk is installed, you can use this by typing:
./android-ndk-r9/build/tools/make-standalone-toolchain.sh --platform=<your desired android platform> --install-dir=<location where you want android toolchain>
This will create a set of build tools which you can use to build arm binaries to run on your device. These tools will be named things like, e.g.
arm-linux-androideabi-gcc
Put those tools in your path and use them to build your library.
I don't know whether cygwin includes a "file" command, but you may be able to determine the architecture of your shared library by typing:
file libapi.so
If it says it's arm, you're good. If it says x86, it won't work (except on an x86 android device, that is).

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.

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

Load a different version of system shared library on Android by NDK?

I am trying to develop an android application by using some native libraries.However, the system shared libraries on android 4.0 and android 4.1.2 are different. To ensure the compatibility, I get the libskia.so file from platform 4.0, and import it into my project. I wish to load this shared library just like using a 3rd party shared library. Unfortunately, while running on android 4.1.2, my application seems still call the system skia library. I have no idea about this and the followings are my Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := sample
LOCAL_SRC_FILES := sample-jni.cpp
LOCAL_CFLAGS := -I /home/WORKING_DIRECTORY/external/skia/include \
-I /home/WORKING_DIRECTORY/external/skia/include/core \
-I /home/WORKING_DIRECTORY/frameworks/base/core/jni/android/graphics \
-I /home/WORKING_DIRECTORY/frameworks/base/include \
-I /home/WORKING_DIRECTORY/frameworks/base/native/include/android \
-I /home/WORKING_DIRECTORY/system/core/include \
-I /home/WORKING_DIRECTORY/external/skia/include/xml \
-I /home/WORKING_DIRECTORY/external/skia/include/images \
-I /home/WORKING_DIRECTORY/external/skia/include/views \
LOCAL_SHARED_LIBRARIES :=skia jnigraphics
include $(BUILD_SHARED_LIBRARY)
include $(LOCAL_PATH)/prebuilt/Android.mk
and the prebuilt makefile
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := skia
LOCAL_SRC_FILES := libskia.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := jnigraphics
LOCAL_SRC_FILES := libjnigraphics.so
include $(PREBUILT_SHARED_LIBRARY)
Any ideas? Or, are there any other methods to ensure compatibility?
I hope you understand that it is not recommended to have any dependencies on the system libraries beyond the stable API. But the open nature of Android allows (both technically and in terms of licensing) to introduce such dependencies. Essentially it means sailing in the non-chartered waters, and being prepared to API changes not only in the next version of the platform, but also in a vendor-provided (i.e. non-AOSP) setups of the same platform level.
Theoretically, you can put a copy of your variation of a system lib into the libs/armeabi-v7a folder of your app, and load it with System.load(fullPath) instead of loadLibrary().
But in practice I believe that system/lib/libskia.so will be loaded in your process before you have a chance to execute your code, and you cannot load two version of the same lib in the same process. Also, an older version of libskia will most likely fail to load on the system because it depends on other system libraries.
The safest way to ensure forward (and vendor) compatibility is to use dynamic linking for the undocumented system features, and perform careful error checking on the way.
But in many cases, the system undocumented APIs are actually quite stable, and the nice people in the Android team of Google do not make breaking changes too often. Therefore, if you link against the 4.0 version of skia your code will most likely simply work on 4.1.2 and on...
Update: In your particular case, when an extra field fTextLocale was added to an old class, you should first of all bless the developers who did not insert this field in the middle of the class declaration. Because now you have a reasonable strategy: use the 4.1.2 headers (with the extra field), link against the 4.0 library (that does not introduce the accessor methods to the new field), and your code will hopefully just work.
You can use a different version of libskia by using dlopen in your native code with parameter RTLD_DEEPBIND. This will overwrite the global symbol table.

Categories

Resources