I have an android application which uses jni and I'm trying to automate build process in Eclipse (using cdt plugin). I need to build my own static library, and I also need to use some precompiled libraries.
That means that I need to
a) build my own shared library (no problems here)
b) after build is complete, copy existing libraries into libs/armeabi folder (because this folder will be cleared during build process I must copy those files after every build)
I have some problems with b). What I'm trying to do is I'm inserting custom shell script (which works when executed as-is) after include $(BUILD_SHARED_LIBRARY) in Android.mk file. Unfortunately, this doesn't work, because apparently /libs/armeabi folder gets cleared only after Android.mk file is complete.
Is that true? Is there a way to insert post-build script into Android.mk? Is there any way I can execute bash script after jni code finished building but before whole build is complete (e.g. before java part is build and application starts executing?)? I though there must be some kind of "post-build" script in eclipse c/c++ project build settings, but there is no such thing.
Here's the complete Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_MODULE := player
LOCAL_SRC_FILES := player.c
include $(BUILD_SHARED_LIBRARY)
$(shell ./copy-libs.sh) #this script will get called, but the files will be erased right after
Well, it looks like there is an easier way to copy .so and .a libs without resorting to custom build scripts.
NDK supports prebuilt modules starting from ndk-r5, and they allow to copy .a or .so libraries into obj/lib folder during build process as needed.
Example and complete description are available in PREBUILTS.html file inside $NDK_INSTALLATION_FOLDER/docs/.
Related
I use some prebuilded so in the prebuild directory of an Android JNI project. The Android mk file for the prebuild libs are like this:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuild
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
But each time when I run ndk-build -B, the so files generated in libs/armeabi changed. So I realized that ndk-build modified the so files rather than simplely copied them. This is annoying when I have to manage these so files with version control software like git, since it is hard to kown if the comitted version is consistent with the so in the prebuild directory. Can I keep them the same?
To check what exactly NDK does on your binary - run it with verbose output: ndk-build V=1. This will print all commands, that NDK does under the hood. Probably it strips debug info, non-exported entries in symbol table with strip.
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.
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
This question seems to have been asked a lot but all were trying to use eclipse to package the library inside the APK.
However, my requirement is to package the library inside the APK (which will later be loaded using System.loadLibrary() through Java) using the Android build system, i.e. i want to write an Android.mk file that does this job.
Requirement:
1. Prebuilt shared library: libTest.so
2. Write an Android.mk file that will package this to libs/armeabi-7 inside the apk.
I don't know much about the build system I am using but the compilation is done using "mm" command after exporting the required environment variables.
When I provide libTest for LOCAL_JNI_SHARED_LIBRARIES, it tries to find it inside its exported paths and fails to find it there and hence build fails.
Can anyone please give any pointers on writing an Android.mk file that will package my prebuild shared library into the APK?
In order to prebuild your native library you have to
Create jni folder in your project folder
Create libs folder in your project folder
Add Adnroid.mk make file to the jni folder, it should looks like
this:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := Test
LOCAL_SRC_FILES := Test.cpp
include $(BUILD_SHARED_LIBRARY)
Note 1: Test.cpp is the main library source file containing implementation of native methods. You can add more sources as a space separated list.
Note 2: Do not include headers, they are included automatically.
Note 3: If you need to enable C++ STL, then create another make file - Application.mk, add it to the jni folder and set APP_STL := stlport_static flag in it.
Then you will have to set up a builder. Refer to this article for how to do that:
After these steps, the builder will create your library in the libs folder which will be automatically packed into the apk when building the whole application.
Note: Your library name should be lowercase, it is a Linux convention. The "lib" prefix will be automatically added, so the final library name will be libtest.so.
Let's say there is one libxxx.so shared library under libs/armeabi/ of project which you want to pack into apk. There are 2 things you need to do in the Android.mk as below:
# 1. Copy .so to out/target/product/***/obj/lib
$(shell cp $(wildcard $(LOCAL_PATH)/libs/armeabi/*.so $(TARGET_OUT_INTERMEDIATE_LIBRARIES))
# 2. Make libxxx to be packed into apk
LOCAL_JNI_SHARED_LIBRARIES := libs/libxxxx
Then you can use apktool to unpack the built apk, you will find the libxxx.so will be located in libs/armeabi*/. It is indeed packed into the apk.
I had two LOCAL_JNI_SHARED_LIBRARIES that I wanted to build into my APK. I manage to do it by setting the following in my Android.mk:
LOCAL_MODULE_TAGS := samples
After re-compiling the module I was able to find both libraries inside the .apk under /lib/.
I'm trying to build a third party library which uses auto-generated
source code files.
In normal case, this kind of files is generated by gnu build tools.
My question is How can I tell the Android NDK build tools to generate and build this kind
of files.
Thanks in advance
The ndk-build tool is a thin wrapper script that calls GNU Make with some command line arguments. You can add any build rules to your Android.mk file that you like written in make, including generating source files.
If you have the generated file name in the LOCAL_SRC_FILES variable together with the rule to generate this file, make will figure it out. This is a minimal example Android.mk that copies "generated.in" to "generated.c" and then compiles it:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkexample
LOCAL_SRC_FILES := generated.c
$(LOCAL_PATH)/generated.c : $(LOCAL_PATH)/generated.in
echo "Generate file"
cp $< $#