Android NDK: How to get compiler architecture in Android.mk dynamically - android

I'm trying to configure Android.mk to cross compile native code to support different chipset namely armeabi, mips, and x86. I know I can configure Application.mk in the following way to compile the source code for different chip set:
APP_ABI := all
This will trigger Android-NDK's build script to compile the source code for all the chipsets. However, I want to dynamically tell Android.mk to look for different static library dependencies compiled with different chip set.
# Get the architecture info
ARCH := ????
include $(CLEAR_VARS)
LOCAL_MODULE:= mylib
LOCAL_SRC_FILES:= build/lib/libxxx_$(ARCH).a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
include $(PREBUILT_STATIC_LIBRARY)
Is this possible to do? If so, can anyone advice how to do so?
Update: I tried something like this in Application.mk:
APP_ABI := armeabi armeabi-v7a mips x64
with Android.mk:
# Get the architecture info
ARCH := $(APP_ABI)
include $(CLEAR_VARS)
LOCAL_MODULE:= mylib
LOCAL_SRC_FILES:= build/lib/libxxx_$(ARCH).a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
include $(PREBUILT_STATIC_LIBRARY)
but it errors with the following:
The LOCAL_SRC_FILES for a prebuilt static library should only contain one item
which makes sense. I want to pass APP_ABI := all in Application.mk and be able to
dynamically reference it. Any ideas?

Check TARGET_ARCH_ABI:
ifeq($(TARGET_ARCH_ABI), armeabi-v7a)
# v7a-specific stuff
endif

There is TARGET_ARCH variable that holds the value of the current ABI being built. You can use it the following way:
ifeq ($(TARGET_ARCH),x86)
LOCAL_CFLAGS := $(COMMON_FLAGS_LIST)
else
LOCAL_CFLAGS := -mfpu=vfp -mfloat-abi=softfp $(COMMON_FLAGS_LIST)
endif
If you specify APP_ABI := armeabi-v7a armeabi mips x86 or APP_ABI := all in your Application.mk you will get each and every separate ABI value.

Related

ANDROID: How to properly link against static libraries while creating shared libraries with dependencies on the static ones

I have to use some c++ code in my android application. This code was used successfully in an iOS project.
The code depends on 2 external libraries: zero-mq and protocol buffers.
I compiled the zmq library as an static library like explained here. I added the static (.a) library and the .jar to my project.
I created the protobuf library with the following configurations:
./configure --host=arm-eabi --with-sysroot=x/android-ndk-r10d/platforms/android-21/arch-arm CC="x/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot x/android-ndk-r10d/platforms/android-21/arch-arm" --enable-cross-compile --with-protoc=protoc LIBS=-lc
make
I changed the real directories to x to make them shorter.
In my Android Project(IDE: Android Studio) I prepared everything which is necessary. I created a JNI Folder and deactivated the auto-creation of the makefiles.
Application.mk:
APP_MODULE := proxy
APP_STL := gnustl_shared
APP_CPPFLAGS := -frtti -fexceptions --std=c++11
APP_ABI := armeabi-v7a ##all later
NDK_TOOLCHAIN_VERSION := 4.9
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := zmq_static
LOCAL_SRC_FILES := zmq/libzmq.a
include $(PREBUILD_STATIC_LIBRARY)
LOCAL_MODULE := protobuf_static1
LOCAL_SRC_FILES := protobuf/libprotobuf.a
LOCAL_EXPORT_C_INCLUDES := google/protobuf protobuf/
include $(PREBUILD_STATIC_LIBRARY)
LOCAL_MODULE := protobuf_static2
LOCAL_SRC_FILES := protobuf/libprotobuf-lite.a
LOCAL_EXPORT_C_INCLUDES := google/protobuf protobuf/
include $(PREBUILD_STATIC_LIBRARY)
LOCAL_MODULE := protobuf_static3
LOCAL_SRC_FILES := protobuf/libprotoc.a
LOCAL_EXPORT_C_INCLUDES := google/protobuf protobuf/
include $(PREBUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := proxy
LOCAL_CFLAGS := -I/include -pthread -lpthread -D__GXX_EXPERIMENTAL_CXX0X__ - frtti
LOCAL_CPPFLAGS := -I/include -pthread -lpthread -D__GXX_EXPERIMENTAL_CXX0X__ -frtti
LOCAL_CPP_FEATURES += exceptions
LOCAL_LDLIBS := -llog
LOCAL_SRC_FILES := \
usersession.cpp\
## LOCAL_ALLOW_UNDEFINED_SYMBOLS := true will compile the code but shutdown on runtime
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\main\jni
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\arm\jni
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\debug\jni
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\armDebug\jni
LOCAL_C_INCLUDES += \zmq
LOCAL_C_INCLUDES += \protobuf
LOCAL_STATIC_LIBRARIES := zmq_static protobuf_static1 protobuf_static2 protobuf_static3
LOCAL_WHOLE_STATIC_LIBRARIES := zmq_static protobuf_static1 protobuf_static2 protobuf_static3
include $(BUILD_SHARED_LIBRARY)
The zmq library is in the subdirectory zmq and the protobuf library is in the subfolder protobuf.
Now the linking of the Objects still does not work. The Error Output when I execute ndk-build:
C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\main\jni>ndk-build
[armeabi-v7a] SharedLibrary : libproxy.so
C:/Users/M/Documents/ndk/sources/cxx-stl/gnu- libstdc++/4.9/include/ext/new_allocator.h:127: error: undefined reference to 'ControlledInstance::ControlledInstan (std::shared_ptr<protogen::Application>, std:
:shared_ptr<protogen::Role>, std::shared_ptr<protogen::User>)'
C:/Users/M/Documents/ndk/sources/cxx-stl/gnu- libstdc++/4.9/include/bits/shared_ptr_base.h:511: error: undefined reference to 'protogen::User::User()'
C:/Users/M/Documents/ndk/sources/cxx-stl/gnu- libstdc++/4.9/include/bits/shared_ptr_base.h:914: error: undefined reference to 'google::protobuf::internal::empty tring_'
C:/Users/M/Dropbox/Workspace/ndk_swig_test/app/src/main//jni/controlledinstance.h :23: error: undefined reference to 'protogen::MetaGraph::~MetaGraph()'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [C:/Users/M/Dropbox/Workspace/ndk_swig_test/app/src/main//obj/local/armeabi- v7a/libproxy.so] Error 1
I tried many versions of the Android.mk and recreated the library more than once with different options which I found all over the internet.
I also looked at dozens of threads on stackoverflow which did not help me.(I'm not allowed to link them because of low reputation)
Additionally i read most of the doc files from the ndk e.g. PREBUILTS.
I added some other directories to my JNI directory e.g. the directory with the original files and directories (compiler, io, stubs...). I think this directory should offer the export of the necessary methods if the prebuild library was successfully linked to my shared library - which is not the case.
I tried far more than I can explain in few minutes and I think it would be overkill if i added everything I've tried because nothing helped.
Because this is my first question I dont have the reputation to include more than 2 links. Sorry for that.
There may probably be other issues as well, but you at least have got a typo - it should be include $(PREBUILT_STATIC_LIBRARY), as in, BUILT, not BUILD.

Android NDK: Linking x86 shared library

I was given a shared library built on Linux x86, let's call it libA.so, and I want to use the function calls provided by this library SDK.
I am having issues building and have a few questions:
1) I will be able to build for x86, but will I be able to build for arm? I believe the answer is no, meaning I cannot run on a Nexus 5 for example.
2) The ndk-build complains of the #include that should be resolved by my LOCAL_SHARED_LIBRARIES. I am not sure why that is. My Android.mk is as follow:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := B
LOCAL_SRC_FILES := B.cpp
LOCAL_SHARED_LIBRARIES := A
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Can someone please help me resolve my Android.mk? I don't understand why it is complaining about my include statement in B.cpp. Please let me know if I can run B in an arm environment, although the SDK I am relying on was built on x86.
If your shared library libA.so has been compiled for linux-x86, it will certainly not run on android x86 targets (mainly because it needs to be linked to Bionic C library instead of glibc), and absolutely not on android arm devices.
Then, to solve your second issue, if you can get properly compiled android shared libraries for your android targets, you would include your library this way:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := A
LOCAL_SRC_FILES := ../libA/prebuilts/$(TARGET_ARCH_ABI)/libA.so # path to libA .so file, depending on the target ABI.
LOCAL_EXPORT_C_INCLUDES := ../libA/includes # path to libA headers.
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := B
LOCAL_SRC_FILES := B.cpp
LOCAL_SHARED_LIBRARIES := A
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

NDK Android - Can't build ARMv5 and V7 at the same time

I'm facing a weird problem.
I'm building a shared library for my Android application.
I can't build both armv5 and armv7 at the same time.
If I do so, I get a lot of errors on my source files at the second run (when the ndk build the armV7 lib) like:
FinderPatternInfo.o: previous definition here
multiple definition of ...
My Application.mk
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8
APP_STL := stlport_static
APP_CPPFLAGS += -fexceptions
It works perfectly if I only set APP_ABI := armeabi or APP_ABI := armeabi-v7a..
Any idea ?
Thank you for your help,
EDIT: Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyModule
MY_LOCAL_INCLUDED_FILES += $(wildcard $(LOCAL_PATH)/*.h)
MY_LOCAL_INCLUDED_FILES += $(wildcard $(LOCAL_PATH)/*.hpp)
MY_LOCAL_INCLUDED_FILES += $(wildcard $(LOCAL_PATH)/bigint/*.h)
... (many includes)
LOCAL_C_INCLUDES := $(subst jni/, , $(MY_LOCAL_INCLUDED_FILES))
MY_LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/*.c)
MY_LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/*.cpp)
MY_LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/bigint/*.c)
.... (many cpp files)
LOCAL_SRC_FILES := $(subst jni/, , $(MY_LOCAL_SRC_FILES))
LOCAL_CFLAGS := -DNO_ICONV
include $(BUILD_SHARED_LIBRARY)
The Android make system parses your Android.mk once for each target, so your MY_LOCAL_SRC_FILES gets a full set of all of your .c and .cpp files twice when there are two targets, but only one of each when there's a single target.
If your first MY_LOCAL_SRC_FILES assignment used := instead of +=, I think it would fix the problem.

Build android native application for many types of CPU

I want to use ffmpeg library in my application so I wrote an Android.mk file as follow:
LOCAL_PATH := $(call my-dir)
TOP_LOCAL_PATH := $(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/android-8/armv5te/include/
LOCAL_CPP_EXTENSION := .cpp
LOCAL_C_EXTENSION := .c
LOCAL_CFLAGS := -O3
LOCAL_MODULE := FilterEngine
LOCAL_SRC_FILES := \
decoding_encoding.c \
LOCAL_LDLIBS := -lm -llog -ljnigraphics -L$(LOCAL_PATH)/android-8/armv5te/lib/ -lavcodec -lavfilter -lavutil -lm -lz
LOCAL_STATIC_LIBRARIES := avcodec avfilter avutil
include $(BUILD_SHARED_LIBRARY)
This make file only builds the library for ARM v5 CPU, to create an ARM v7 build of the library I have to modify the Android.mk file (change from armv5te to armv7a). How can I specify 2 types of CPU in the make file so I can build the library for both CPUs at one.
Thanks in advance.
In your jni folder make "Application.mk" and add the desired target architectures, for example:
APP_ABI := armeabi armeabi-v7a x86
Next, change your Android.mk to use: $(TARGET_ARCH_ABI) where you have the architecture hardcoded.
I'm doing something similar with FFmpeg. Here is a link for further reference:
http://sourceforge.net/p/servestream/code/1217/tree/trunk/jni/
Let me know if you have any additional questions.

Build shared library linking to other not standard shared libarary

I have some two shared libraries and header for them.
I want to build third shared library using functions from previous two libs.
Have problem with makefile i think. When i try to build receive this:
Android NDK: /cygdrive/d/.../jni/Android.mk: Cannot find module with tag 'shared1' in import path
Android NDK: Are you sure your NDK_MODULE_PATH variable is properly defined ?
Android NDK: The following directories were searched:
Android NDK:
/cygdrive/d/.../jni/Android.mk:36: *** Android NDK: Aborting. . Stop.
structure of my project:
jni/
- myfile.c
- Android.mk
jni/dec/
- lot of header files
jni/enc/
- lot of header files
libs/armeabi/
- shared1.so
- shared2.so
also Android.mk sourse:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/dec \
$(LOCAL_PATH)/enc
LOCAL_SHARED_LIBRARIES := shared1 shared2
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := myfile.c
LOCAL_LDLIBS += -lOpenSLES
LOCAL_LDLIBS += -llog
LOCAL_LDLIBS += -landroid
include $(BUILD_SHARED_LIBRARY)
$(call import-module, shared1)
$(call import-module, shared2)
Take a look to this question: Android JNI APK Packing
You need to give another name for libs/armeabi/ folder to avoid conflicts with NDK build and add the following code before the include $(CLEAR_VARS) statement:
include $(CLEAR_VARS)
LOCAL_MODULE:=shared1
LOCAL_SRC_FILES:=3rdparty_libs/shared1.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:=shared2
LOCAL_SRC_FILES:=3rdparty_libs/shared2.so
include $(PREBUILT_SHARED_LIBRARY)
As I understand it, the correct method is to use ndk-build and not invoking the compiler directly.
In Android.mk you need to specify a module for each static library you want to compile, and then specify that your shared library should use it.
Example of a modified Android.mk file of the hello-jni sample project:
LOCAL_PATH := $(call my-dir)
# Define vars for library that will be build statically.
include $(CLEAR_VARS)
LOCAL_MODULE := <module_name>
LOCAL_C_INCLUDES := <header_files_path>
LOCAL_SRC_FILES := <list_of_src_files>
# Optional compiler flags.
LOCAL_LDLIBS = -lz -lm
LOCAL_CFLAGS = -Wall -pedantic -std=c99 -g
include $(BUILD_STATIC_LIBRARY)
# First lib, which will be built statically.
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_STATIC_LIBRARIES := <module_name>
LOCAL_C_INCLUDES := <header_files_path>
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
If you want control over which modules to compile when you run ndk-build you can create create a Application.mk file (in the same directory as Android.mk) and list all the modules as in the following example:
APP_MODULES := <module_name_1> <module_name_2> ... <module_name_n>
I think it Helps you

Categories

Resources