I am currently writing a genre classification application as my final year project in Computer Engineering. I initially wrote the feature extraction code (implementing FFTW) in C and now I need to implement it on Android via the NDK.
This is my first NDK project so I'm still getting the hang of things but I have compiled the FFTW3 library for Android according to this guide. I didn't do the very last step because I didn't think it was right for what I need.
My question is how do I, after the compile step, use the library in the main NDK application that calls on it? Do I everything normally in Application.mk just with LOCAL_STATIC_LIBRARIES set to the libfftw3.a that I just compiled? And then I don't need to have any -lfftw3 linker flags like I normally would right?
You can use prebuit FFTW library (no matter how did you build it).
Or you can build FFTW in Android.mk makefile with the whole project.
Android.mk content will be:
# Prebuilt FFTW library
include $(CLEAR_VARS)
LOCAL_MODULE := fftw
include $(PREBUILT_STATIC_LIBRARY)
# or
# Build FFTW library
include $(CLEAR_VARS)
LOCAL_MODULE := fftw
# TODO put your static libs build flags
include path_to_fftw_sources/$(LOCAL_MODULE).mk
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := YourProject
# TODO put your shared lib build flags
include path_to_your_project/$(LOCAL_MODULE).mk
LOCAL_STATIC_LIBRARIES += fftw
include $(BUILD_SHARED_LIBRARY)
I have written path_to_fftw_sources/$(LOCAL_MODULE).mk for building fftw static library and path_to_your_project/$(LOCAL_MODULE).mk for building your shared library. It is often better to put LOCAL_SRC_FILES and LOCAL_C_INCLUDES to the separate .mk file.
You can read more about Android.mk file in docs/ANDROID-MK.html document in your NDK distribution.
Related
I've been trying to perform some native library builds for my Android App. More specifically performing ndk-build, with the help of some prebuilt shared libraries. One of the modules (let's call it pyjni) depends on those prebuilt shared libraries. Therefore my Android.mk consists of two modules for the prebuilt and to-be-built libraries respectively, as recommended for android ndk development.
This is my Android.mk file for the App:
LOCAL_PATH := $(call my-dir)
TARGET_ARCH_ABI := armeabi-v7a
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(LOCAL_DIR)/libs/$(TARGET_ARCH_ABI)/libprebuilt.so
LOCAL_MODULE := prebuilt
include $(PREBUILT_SHARED_LIBRARY)
# Build libpyjni.so
include $(CLEAR_VARS)
LOCAL_MODULE := pyjni
LOCAL_SRC_FILES := pyjni.c
LOCAL_C_INCLUDES:= $(LOCAL_DIR)/include/$(TARGET_ARCH_ABI)/
LOCAL_SHARED_LIBRARIES := prebuilt
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
Build turns out fine. In fact, when examining the .APK both the pre-built and built shared libraries are packaged inside # lib/armeabi-v7a. So far so good.
However, when trying to load the built shared library as System.loadLibrary("pyjni") during the App execution, it crashes notifying the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library ".../app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libprebuilt.so" not found.
I can succesfully load the prebuilt library using System.loadLibrary("prebuilt"). So at this point I suspect it is an issue on how the prebuilt shared library is being packaged or rather how LOCAL_SHARED_LIBRARIES is working. In the app's build.gradle file the sourceSets.main.jniLibs.srcDirs points to the directory where libprebuilt.so is placed. To avoid packaging issues with multiple instances of the prebuilt library file, the gradle file specifies
packagingOptions{
pickFirst 'lib/armeabi-v7a/libprebuilt.so'
}
At this point I'm confused with how the link created by LOCAL_SHARED_LIBRARIES is working on execution.
In my Android application, I have quite a few open-source C++ projects that are built as static libraries. Essentially, Android.mk builds all the libraries as static and links them all to create my final core.so library.
Our nightly build checks out all the files from the source control in a clean directory and builds everything that is needed.
I am looking at how I can optimize our nightly build. As the third-party code does not change (may be once every six months), I would like to build them just once and check in the generated libs. I am guessing these libs would have a ".a" extension. The nighly build will simply check out these libs and link them to create my final core.so.
Basically, I am hoping I can break my existing Android.mk into two different ones - one for building static libraries and one for building the final shared library that the Android code can use.
I am wondering if this is possible. Regards.
You're looking for prebuilt library support.
Assuming your static library declaration looks something like this:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)
you can make it use a prebuilt instead:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := libs/foo.a
include $(PREBUILT_STATIC_LIBRARY)
and include in your core lib just the same:
include $(CLEAR_VARS)
LOCAL_MODULE := myCore
LOCAL_SRC_FILES := core/core.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
So you could have a seperate Android.mk, or just use a conditional variable.
ifeq ($(USE_PREBUILT_LIBS),)
# declare with BUILD_STATIC_LIBRARY
else
# declare with PREBUILT_STATIC_LIBRARY
endif
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.
I have a program I am porting that links together multiple libraries when creating the executable. I have built all those libraries using the stand alone toolchain and using the standalone toolchain I am able to create an executable that works on an android device. So, it seems like the libraries I have built are functional. Now I am trying to incorporate those libraries with an app. So, in my android.mk I have something like this:
LOCAL_PATH := $(call my-dir)
ROOT_PATH := $(LOCAL_PATH)
include $(call all-subdir-makefiles)
include $(CLEAR_VARS)
LOCAL_PATH = $(ROOT_PATH)
LOCAL_MODULE := test-libs
LOCAL_STATIC_LIBRARIES := staticA
LOCAL_SHARED_LIBRARIES := sharedA sharedB sharedC sharedD
LOCAL_SRC_FILES := test-libs.c
include $(BUILD_SHARED_LIBRARY)
For each of the libraries, I have a Android.mk like this
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := sharedA
LOCAL_SRC_FILES := sharedA.so
include $(PREBUILT_SHARED_LIBRARY)
When I then build my project (in eclipse), I get this:
C:/ndk/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a(unwind-arm.o): In function `__gnu_unwind_pr_common':
/cygdrive/c/ndk/android-ndk-r7b/build/core/build-binary.mk:314: recipe for target `obj/local/armeabi/libtest-libs.so' failed
/tmp/ndk-digit/src/build/../gcc/gcc-4.4.3/libgcc/../gcc/config/arm/unwind-arm.c:1237: undefined reference to `__cxa_call_unexpected'
Any thoughts on what is going wrong?
Also, the static library and one of the shared libraries have no dependencies on anything and if I only include them all is cool. One of my shared libraries only had a dependency on the static library. If I only include those, but when I include the others, which have dependencies on other shared libraries, this problem occurs.
Update 1: Ok it appears to be because the APP_STL setting in my Application.mk was being ignored. All I have in my Application.mk is:
APP_STL := gnustl_shared
If I copy over the libgnustl_shared.so and treat it like another prebuilt shared lib, my problem is gone. Any idea why the APP_STL is not working properly. Note, I could have screwed something up. I just upgraded to using 7b. Using gnustl_shared used to work for me with other apps. Rolling back to 7 doesn't fix it. I think I have messed something up in Eclipse. I use Eclipse (windows) with sequoyah.
It looks like the linker is giving you an error. What you should do is the following:
Add a LOCAL_LDLIBS under your LOCAL_MODULE := test-libs. Here you need to include all the libraries you link against when you compile your pre-compiled libraries. So for example:
LOCAL_LDLIBS := -lgnustl_shared -lgcc -llog -landroid -lstdc++
Basically you need to identify what library contains the function __cxa_call_unexpected. A quick google shows that it's probably in libstdc++. Make sure that you also link with this library when creating your pre-compiled libraries.
I'm thinking it might have something to do with exceptions support.
Are you using exceptions in your code and if so are you compiling with a runtime library that supports exceptions? (and compiling with exceptions on)?.
There is more on this in the CPLUSPLUS-SUPPORT and STANDALONE-TOOLCHAIN files in the ndk docs.
I've observed a similar problem when one of my projects which contains only C source files (*.c) references another project that contains a c++ file(*.cpp). Application.mk files for both projects had APP_STL := gnustl_shared in them. The ndk version is ndk7e.
The solution was adding an empty C++ file (dummy.cpp) to the project that contained only .c files. Supposedly ndk understood that this project should be linked against the gnustl_shared and the build succeeded.
I have written an Android app. It uses a main C-code module and a linked-in C-code module. Now I want to replace the linked-in module with an ARM assembler module. Anyone have a simple example?
Here's an example of Android.mk file that will build sourcetree containing assembly. To see a complete example check the hello-neon sample distributed in the NDK package.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm # remove this if you want thumb mode
LOCAL_ARM_NEON := true # remove this if you want armv5 mode
LOCAL_CFLAGS := -std=c99 -pedantic -v
LOCAL_SRC_FILES := # list your C, C++ and assembly sources here.
# assembly source files ends with extension .S
# add .arm after the extension if you want to compile in armv5 mode (default is thumb)
# add .arm.neon to compile in armv7 mode
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := #the name of your shared library
include $(BUILD_SHARED_LIBRARY)
I wrote a tutorial to do exactly this.
http://www.eggwall.com/2011/09/android-arm-assembly-calling-assembly.html
ARM assembly in Android isn't difficult, but there are many moving pieces: you need an assembly source, a C stub, a Makefile, and Java stub "native" methods that call the underlying assembly code.
You could download the source code from the link above, and see how it works. Once you have one working example, it is easy to poke and make it fit your need.
I Saw the article by vikram I have an opinion that for beginners, it is better to build and run assembler code in Android using android source code.
e.g. you can create a module with the specification "BUILD_EXECUTABLE" in the Android.mk
You can have a main function inside the C code and have the assembler code built along with main.c
You can add such a module even under gingebread/frameworks/base/<mymodule>