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.
Related
I have an NDK project where I build the shared libraries using the cross-compiler and standard gnu make utils. That is done with a separate script. But for the purpose of using the libraries in my project, I would like my Android.mk process to call my script to generate the shared library if it hasn't already been built, and then have Android.mk wrap it using the PREBUILT_SHARED_LIBRARY process.
Currently, if I run my script offline to generate libmy_so.so, then the following makefile will work. However, if I don't run the script explicitly first, I get the following error:
Android NDK: ERROR:/path_to_project/Android.mk:my_module: LOCAL_SRC_FILES points to a missing file
and my script is never called, so the make process is failing before even trying to resolve the dependency.
include $(CLEAR_VARS)
LOCAL_MODULE := my_module
LOCAL_SRC_FILES := libmy_so.so
LOCAL_EXPORT_CFLAGS := # some stuff
LOCAL_EXPORT_LDLIBS := # some stuff
$(LOCAL_PATH)/libmy_so.so:
echo "generate file"
$(shell run_script_that_creates_libmy_so.so)
include $(PREBUILT_SHARED_LIBRARY)
Is there a clean solution to this? I am even ok with running the script automatically as a preprocessing step (I can always have my script quietly exit if the file exists already), but I have not found an incantation that allows the LOCAL_SRC_FILES variable to point to a non-existent file. I have considered placing a dummy libmy_so.so to start, but that is an ugly hack.
Found a hack -- better way?
I found a hack. The makefile prebuilt-library.mk in the NDK contains the following lines:
ifndef prebuilt
$(call __ndk_info,ERROR:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): LOCAL_SRC_FILES points to a missing file)
$(call __ndk_info,Check that $(prebuilt_path) exists, or that its path is correct)
$(call __ndk_error,Aborting)
#endif
I created a copy of this file (and prebuilt-shared-library.mk to which I reference my copy of prebuilt-library.mk) and commented those lines out to stop the error. Then the trick is to make some target that is evaluated first depend on the file I want to generate. After digging through the .mk scripts in the NDK, I found that libraries serves the purpose. By adding libraries: $(LOCAL_PATH)/libmy_so.so to Android.mk, it will finally do what I want.
include $(CLEAR_VARS)
LOCAL_MODULE := my_module
LOCAL_SRC_FILES := libmy_so.so
LOCAL_EXPORT_CFLAGS := # some stuff
LOCAL_EXPORT_LDLIBS := # some stuff
$(LOCAL_PATH)/libmy_so.so:
echo "generate file"
$(shell run_script_that_creates_libmy_so.so)
libraries: $(LOCAL_PATH)/libmy_so.so
include /path/to/my/mk/files/prebuilt-shared-library.mk
This is obviously less than ideal as I would like to make sure my makefiles mature with newer versions of the NDK, but it does the trick. Still interested in more elegant solutions.
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 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 tried to add a prebuilt APK to my Android build. The APK contains several shared libraries (*.so files). It compiles without problem, but I still get an error from the app indicating that the libraries cannot be found.
Why could this be?
Here is the android.mk code:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := apkwithso
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_REQUIRED_MODULES := libx liby libz
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
include $(BUILD_PREBUILT)
libx, y, z are my libx.so, liby.so, and libz.so
I also tried to copy the .so manually from the APK to the out lib directories but it didn't work.
I am compiling with Android 4.1.2 for Galaxy Nexus Maguro.
I've had this problem myself, the reason is that when APK files are included in a build they are essentially bypassing the installation process. This installation process is the point at which any shared libraries are extracted from the apk and put in the appropriate place, ergo if that never happens the libraries will not be available. This is because packages that are built from source during the AOSP build either have their prebuilt shared libraries included during that build process or their libraries are also built from source, and in either case those libraries are put in the appropriate place.
For this reason in addition to the apk module itself you should add the following in the same .mk file:
include $(CLEAR_VARS)
LOCAL_MODULE := libapkwithso
LOCAL_SRC_FILES := lib/libapkwithso.so # or wherever your so is
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_SUFFIX := .so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
include $(BUILD_PREBUILT)
Then add:
LOCAL_REQUIRED_MODULES := libapkwithso
BUILD_PREBUILT calls prebuild.mk script. The description of this script is the following:
Standard rules for copying files that are prebuilt
It does not tell that the application will be installed. So I think that is why your application cannot find the libraries.
The solution is to extract libraries from the package and copy them separately from the application. The details how to do this you can find here.
Files can also be be specified in aospSource:destinationOnImage format like this in the device-partial.mk when adding a custom vendor directory:
PRODUCT_COPY_FILES += \
vendor/your-custom-vendor/your-device/proprietary/libx.so:system/lib/libx.so
You can add pretty much anything you like here (other than .apk files), and it will be copied to your image.
My Instructions is not about your error! But it may be helpful for similar error
If you try to copy prebuilt apk using:
PRODUCT_COPY_FILES += $(LOCAL_PATH)/prebuilt/filename.apk
and you getting this error:
Prebuilt apk found in PRODUCT_COPY_FILES: ... , use BUILD_PREBUILT instead!. Stop.
You can remove this check my modify the file build/core/MakeFile and comment this lines:
define check-product-copy-files
$(if $(filter %.apk, $(call word-colon, 2, $(1))),$(error \
Prebuilt apk found in PRODUCT_COPY_FILES: $(1), use BUILD_PREBUILT instead!))
endef
by inserting # before each line
Too add multiple libraries to one apk one additional section (as in answer of Justin Buser) should be added for each separate 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/.