Shared library and Android NDK - android

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

Related

How to tell toolchain for a Device? In order to build native application in C

I have a shared library in C. I want to compile and run a test application on my android device.
As for as my understanding goes, here is what I think I have to do:
Cross compile the library for the arm device using its tool chain
Make an android.mk file and compile using NDK (I followed this link : build-cc-executables-for-android-using-ndk)
I modified the android.mk file to add a shared library,
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# give module name
LOCAL_MODULE := depend1
LOCAL_SRC_FILES := libdepend1.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
# give module name
LOCAL_MODULE := depend2
LOCAL_SRC_FILES := libdepend2.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
# give module name
LOCAL_MODULE := test
# list your C files to compile
LOCAL_SRC_FILES := test.c
# this option will build executables instead of building library
include $(BUILD_EXECUTABLE)
The project compiles. I get my executable in the libs folder.
On running the executable on android shell using adb I get the following error:
Init: Error opening /data/local/project/depend1.so: dlopen failed: could not load library "depend2.so" needed by "depend1.so"; caused by could not load library "libgcc_s.so.1" needed by "depend2.so"; caused by library "libgcc_s.so.1" not found
(NOTE: dlopen is part of my code)
It is not able find a library that is part of the toolchain, I didnt find this library in /system/lib of the device, which leads me to my first question - Am i using the right toolchain (the one I used is arm-none-linux-gnueabi)
Secondly am I building it correctly for android?
This library use Cmake or automake?
For Cmake you just need to properly confugure it (how to)
Example: cmake -DANDROID_NDK=path/to/ndk -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake --DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=android-21 ..
For automake you should use prebuilt GCC toolchains (but GCC deprecated in NDK) or create new own standalone toolchain (how to)
This toolchains are 100% valid for cross-compiling for Android
If you still want use ndk-build you can read this link (I don't use it, so I can help further only with Cmake and automake)

openCV for Android - NOT opencv-android-sdk

I want to use some native c++ code/library in my Android application. The c++ part is heavily based on openCV.
I am aware of opencv-android-sdk and have seen plenty of detailed tutorials on how to do it with Android Studio (like this one), but these all just use the opencv-android-sdk that only supports a limited subset of openCV functions (I am not talking about those that do not make sense on a mobile device, like gpu-related functionalities, but some other functions that simply do not exist in the opencv-android-sdk and I need them for the c++ code).
Anyway, my question is: can I somehow compile and use the "full set of modules" of openCV in my Android Studio project (using NDK, etc.)?
I saw also this one, and it claims that "[it] will build most of the OpenCV modules [for android]", but it is not clear to me how to use it...
Any hint would be highly appreciated!
OK! I guess I figured it out!
Basically one needs to follow this tutorial, but just replace the path in Android.mk to point to the compiled full version of openCV, instead of openCV-Android-SDK (as well as some other small changes; for those I just copy here what I have in Android.mk and Application.mk).
Eventually, my Android.mk looks like this (OPENCVROOT need to be set properly):
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCVROOT:= /path/to/opencv-2.4.10/platforms/build_android_arm
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}/OpenCV.mk
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS += -llog
LOCAL_MODULE := hello
include $(BUILD_SHARED_LIBRARY)
And Application.mk looks like this:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-19
Just a short note on compiling openCV with Android NDK:
For compiling full openCV using NDK, one can still use the method mentioned here; the description is based on NDK-r8e, but if needed, one can download NDK-r10d and use it instead. I had to turn-off cuda-related parts in openCV source, in order to successfully compile it with NDK (just adding -D WITH_CUDA=OFF to opencv-2.4.10/platforms/scripts/cmake_android_arm.sh , in the last line, after cmake, does the job!). In case you need to have the nonfree modules (like SURF and SIFT, do NOT clone it from github, just download it in a single zip from here; I used version 2.4.10 by the way).
Now I have access to almost all openCV functions in the native c++ code that I am integrating into my Android App!
I hope this helps others, too!
You should investigate JNI (The Java Native Interface) which is a means of wrapping C libraries with Java.
Also you may want to consider getting hold of this book: Mastering OpenCV with Practical Computer Vision Projects
Which goes into this in some detail.

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.

Accessing headers for NDK from Android Library Project

I'm currently implementing a custom Logging mechanism that I need to be accessible from both native and Java code. The fundamentals of the logging are implemented in C/C++ with a Java wrapper, and the two together are being built as an android Library Project.
The issue at hand is that while my Java code can access the Library project output, there doesn't seem to be a way for my native code to access the native .so or headers from the Library project. Is there an additional step I'm missing or is this just a limitation of the current ADT? More specifically, is there a makefile/eclipse configuration that will address the things I'm used to getting out of Library projects in general? (Build .so as needed, import rebuilt .so, import relevant headers for c/c++ compilation, etc.)
I don't think it's a limitation. We are supposed to declare native code dependencies in Android.mk and Application.mk
Worked out a way to get what I wanted - most of the information is (of course) in the NDK documentation, but what I was trying to do isn't 100% supported within the ADT. It should also be noted that I'm currently stuck developing in a windows environment, so much of this might be easier or unnecessary in Linux. The first key is the $(call import-module ...) macro. Within your library project, move the source files and the Android.mk folder into a named directory you can locate later. My Library project directory looked like this:
MyProject
> src
> res
v jni
- Application.mk
v MyLib
- source.cpp
- source.h
- Android.mk
I also had to edit my Application.mk to point to the project:
APP_PROJECT_PATH := <path-to-my-project>
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/MyProject/Android.mk
Annoyingly, this broke my Android.mk in ways unforseen until I added a ./ to my source files. Also you need to export your includes for linking:
LOCAL_SRC_FILES := ./source.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
Ensure that the system path variable NDK_MODULE_PATH is set to include your library's JNI directory, e.g. <path-to-my-project>/jni (Note: I had to restart eclipse after I did this).
In the receiving application's Android.mk file (the one you'd like to link natively to your app), import the module:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyNativeProject
LOCAL_SRC_FILES := source.cpp
LOCAL_CFLAGS := -DANDROID_NDK -g -std=c99
LOCAL_SHARED_LIBRARIES := MyLib
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
$(call import-module, IntelLog)
At this point everything built perfectly, but the APK packager didn't like the generated .so binary being included twice (once from the Library project's natural import process, and again from the import-module call). To solve this, clean the library and don't build it again! the import-module call will build the .so and import it into your project. (Obviously, if your project only requires the Java API, you would need that .so file to be built). Congratulations! you have a functional (if not straightforward) build process with a hybrid native/Java Library

Android NDK Plugin trouble reading OpenGL header

I am trying to use the new android NDK plugin that comes with ADT to write an OpenGL ES application. I am getting a getting undefined references for all my gl functions although I have added the correct path to the NDK under Preferences -> Android -> NDK and set the correct Paths and Symbols in the project properties. I am using Windows.
And yet I still get undefined references like so:
I am using CDT 8.0.2 because apparently the newer version broke the way the NDK plugin looks for paths. I am using ADT 20.0.3. My eclipse version is Juno 4.2.0. Does anyone know why it cant find the headers that are clearly there?
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libgweng
LOCAL_SRC_FILES := game.cpp
include $(BUILD_SHARED_LIBRARY)
You don't need to do this with the NDK, just write an appropriate makefile for an Android build.
Look at the source code in the hello-gl2 example that comes with the NDK; give attention to the Android.mk of this example.

Categories

Resources