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
Related
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).
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).
As you know, Android L will support devices (mobile phones) based on a 64-bit target CPU (ARM).
So I am preparing for native code binaries (.so file extension) for that kind of 64-bit Android phone.
How can I build an .so binary for a 64-bit target with Android NDK?
According to my investigation, setting the following variable fixes my question in Application.mk.
APP_ABI := arm64-v8a
Coould anyone confirm my answer ?
Thanks.
you need to use the latest version of the NDK (right now it's r10c).
If you set APP_ABI := all inside Application.mk, your native library will be compiled for all the supported architectures, including the 64bit ones.
You can also specify a list of the architectures you want to compile against, for example:
APP_ABI := x86 armeabi-v7a arm64-v8a x86_64
You can all the architectures you want to compile against, for example:
APP_ABI := all
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.
I have a native library that I am using in my Android app. It has 4 .so files(armeabi,armeabi-v7a, mips, x86) in the libs folder. Now, the thing is, each .so file is close to 10 mb. This is making the total apk size around 40 mb. I want to include just one .so file for the relevant architecture and not include the other .so files at all .
This is my application.mk :
# When we build for google play, we build 4 different apk's, each with
# a different version, by uncommenting one of the pairs of lines below.
# Suppose our base version is X:
# Version X: armeabi
#APP_PLATFORM=android-8
#APP_ABI := armeabi
# Version X+1: armeabi-v7a (Much faster due to the availability of hardware
# FP, but cannot be run in the emulator).
APP_PLATFORM=android-8
APP_ABI := armeabi
# Version X+2: x86 (Requires android-9, so a change needs to be made in
# AndroidManifest.xml too)
#APP_PLATFORM=android-9
#APP_ABI := x86
# Version X+3: mips (Requires android-9, so a change needs to be made in
# AndroidManifest.xml too)
#APP_PLATFORM=android-9
#APP_ABI := mips
ifdef NDK_PROFILER
# The profiler doesn't seem to receive ticks when run on release code.
# Accordingly, we need to build as debug - but this turns optimisations
# off, which is less than ideal.
APP_OPTIM := debug
APP_CFLAGS := -O2
else
APP_OPTIM := release
endif
ifdef V8_BUILD
APP_STL := stlport_static
endif
ifdef MEMENTO
APP_CFLAGS += -DMEMENTO -DMEMENTO_LEAKONLY
endif
# If the ndk is r8b then workaround bug by uncommenting the following line
#NDK_TOOLCHAIN_VERSION=4.4.3
# If the ndk is newer than r8c, try using clang.
#NDK_TOOLCHAIN_VERSION=clang3.1
I am new at ndk, so I might be going wrong somewhere, but I have a hunch that this Application.mk doesnt get executed at all. How do I get this to run? Because even though APP_ABI := armeabi is there, I get ALL the .so files in my compiled apk(opened using winrar).
My question is, How do I tell the .mk to build for specific architectures? And how are my changes going to be reflected? I just click on RUN (the green triangle in eclipse).
PS:
This is a 3rd party library that I have downloaded, so I dont really know the code inside