Refactor Android NDK make files into modules - android

I'm having trouble refactoring some make files into manageable modules.
Following is the structure I try to accomplish:
jni/Android.mk
jni/Application.mk
jni/libobj/Android.mk
jni/libpng/Android.mk
jni/libzip/Android.mk
jni/freetype/Android.mk
jni/ftgles/Android.mk
jni/qcar/Android.mk
jni/imagetargets/Android.mk
Note: I started from the Vuforia SDK ImageTargets example and added
some other libraries like reading OBJ, PNG and ZIP files. I've also
included the freetype and ftgles library.
I call the other make files from my the root Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include jni/libobj/Android.mk
include jni/libpng/Android.mk
include jni/libzip/Android.mk
include jni/freetype/Android.mk
include jni/ftgles/Android.mk
include jni/qcar/Android.mk
include jni/imagetargets/Android.mk
You can see all make files in a gist on github.
The compiler gives following error:
Install : libFTGLES.so => libs/armeabi/libFTGLES.so Compile++
arm : ImageTargets <= ImageTargets.cpp
jni/imagetargets/ImageTargets.cpp:44:24: fatal error: libpng/png.h: No
such file or directory compilation terminated. make: *
[obj/local/armeabi/objs/ImageTargets/ImageTargets.o] Error 1
Any idea how to make the libpng (and other modules) headers available for the imagetargets module?

I think that specifying the path to the includes in each sub-makefile using LOCAL_EXPORT_C_INCLUDES would ensure that the headers are available when building the final module.
Check the documentation for this flag in the NDK documentation (available in your NDK directory), but from what I understand, it will do exactly what you're trying to do: automatically export the include path of each sub-module to the final module.

Related

Getting jniLibs to work with Gradle 2.10 [duplicate]

I want to use a existing native library from another Android project, so I just copied the NDK built library (libcalculate.so) to my new Android project. In my new Android project I created a folder libs/armeabi/ and put libcalculate.so there. There is no jni/ folder. My testing device has ARM architecture.
In my java code I load the library by:
static{
System.loadLibrary("calculate");
}
When I run my new android project, I got error:
java.lang.UnsatisfiedLinkError: ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
So, as error says, the copied native library is not in /verdor/lib or /system/lib , how to resolve this problem in my case?
(I unziped the apk package, under lib/ there is libcalculate.so)
====UPDATE=====
I also tried to create a jni/ folder under project root, and add an Android.mk file under jni/. The content of Android.mk is:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
Then, under project root, I executed ndk-build . After that, the armeabi/ and armeabi-v7a/ directories are generated by ndk-build (with libcalculate.so inside the folder).
Then I run my maven build the project successfully. In the final apk package, there are:
lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so
But when I run my app, the same error throw:
java.lang.UnsatisfiedLinkError: ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
To root cause (and maybe solve your issue in the same time), here is what you can do:
Remove the jni folder and all the .mk files. You don't need these nor the NDK if you aren't compiling anything.
Copy your libcalculate.so file inside <project>/libs/(armeabi|armeabi-v7a|x86|...) . When using Android Studio, it's <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), but I see you're using eclipse.
Build your APK and open it as a zip file, to check that your libcalculate.so file is inside lib/(armeabi|armeabi-v7a|x86|...).
Remove and install your application
Run dumpsys package packages | grep yourpackagename to get the nativeLibraryPath or legacyNativeLibraryDir of your application.
Run ls on the nativeLibraryPath you had or on legacyNativeLibraryDir/armeabi, to check if your libcalculate.so is indeed there.
If it's there, check if it hasn't been altered from your original libcalculate.so file: is it compiled against the right architecture, does it contain the expected symbols, are there any missing dependencies. You can analyze libcalculate.so using readelf.
In order to check step 5-7, you can use my application instead of command lines and readelf: Native Libs Monitor
PS: It's easy to get confused on where .so files should be put or generated by default, here is a summary:
libs/CPU_ABI inside an eclipse project
jniLibs/CPU_ABI inside an Android Studio project
jni/CPU_ABI inside an AAR
lib/CPU_ABI inside the final APK
inside the app's nativeLibraryPath on a <5.0 device, and inside the app's legacyNativeLibraryDir/CPU_ARCH on a >=5.0 device.
Where CPU_ABI is any of: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64. Depending on which architectures you're targeting and your libs have been compiled for.
Note also that libs aren't mixed between CPU_ABI directories: you need the full set of what you're using, a lib that is inside the armeabi folder will not be installed on a armeabi-v7a device if there are any libs inside the armeabi-v7a folder from the APK.
In gradle, after copying all files folders to libs/
jniLibs.srcDirs = ['libs']
Adding the above line to sourceSets in build.gradle file worked. Nothing else worked whatsoever.
In my case i must exclude compiling sources by gradle and set libs path
android {
...
sourceSets {
...
main.jni.srcDirs = []
main.jniLibs.srcDirs = ['libs']
}
....
The reason for this error is because there is a mismatch of the ABI between your app and the native library you linked against. Another words, your app and your .so is targeting different ABI.
if you create your app using latest Android Studio templates, its probably targeting the arm64-v8a but your .so may be targeting armeabi-v7a for example.
There is 2 way to solve this problem:
build your native libraries for each ABI your app support.
change your app to target older ABI that your .so built against.
Choice 2 is dirty but I think you probably have more interested in:
change your app's build.gradle
android {
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a'
}
}
}
Are you using gradle? If so put the .so file in <project>/src/main/jniLibs/armeabi/
I hope it helps.
For reference, I had this error message and the solution was that when you specify the library you miss the 'lib' off the front and the '.so' from the end.
So, if you have a file libmyfablib.so, you need to call:
System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so'
Having looked in the apk, installed/uninstalled and tried all kinds of complex solutions I couldn't see the simple problem that was right in front of my face!
This is an Android 8 update.
In earlier version of Android, to LoadLibrary native shared libraries (for access via JNI for example) I hard-wired my native code to iterate through a range of potential directory paths for the lib folder, based on the various apk installation/upgrade algorithms:
/data/data/<PackageName>/lib
/data/app-lib/<PackageName>-1/lib
/data/app-lib/<PackageName>-2/lib
/data/app/<PackageName>-1/lib
/data/app/<PackageName>-2/lib
This approach is hokey and will not work for Android 8; from https://developer.android.com/about/versions/oreo/android-8.0-changes.html
you'll see that as part of their "Security" changes you now need to use sourceDir:
"You can no longer assume that APKs reside in directories whose names end in -1 or -2. Apps should use sourceDir to get the directory, and not rely on the directory format directly."
Correction, sourceDir is not the way to find your native shared libraries; use something like. Tested for Android 4.4.4 --> 8.0
// Return Full path to the directory where native JNI libraries are stored.
private static String getNativeLibraryDir(Context context) {
ApplicationInfo appInfo = context.getApplicationInfo();
return appInfo.nativeLibraryDir;
}
Try to call your library after include PREBUILT_SHARED_LIBRARY section:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
#...
LOCAL_SHARED_LIBRARIES += libcalculate
Update:
If you will use this library in Java you need compile it as shared library
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)
And you need deploy the library in the /vendor/lib directory.
You could just change ABI to use older builds:
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a'
}
...
}
You should also use deprecated NDK by adding this line to gradle.properties:
android.useDeprecatedNdk=true
actually, you can't just put a .so file in the /libs/armeabi/ and load it with System.loadLibrary. You need to create an Android.mk file and declare a prebuilt module where you specify your .so file as a source.
To do so, put your .so file and the Android.mk file in the jni folder.
Your Android.mk should look something like that:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)
Source : Android NDK documentation about prebuilt
please add all suport
app/build.gradle
ndk {
moduleName "serial_port"
ldLibs "log", "z", "m"
abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86","x86_64","mips","mips64"
}
app\src\jni\Application.mk
APP_ABI := arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "x86", "armeabi", "mips"
}
}
Just add these line in build.gradle app level
In my experience, in an armeabi-v7a mobile, when both armeabi and armeabi-v7a directories are present in the apk, the .so files in armeabi directory won't be linked, although the .so files in armeabi WILL be linked in the same armeabi-v7a mobile, if armeabi-v7a is not present.

importing custom SO file to AOSP

I've built an AOSP system service following this tutorial:
http://www.androidenea.com/2009/12/adding-system-server-to-android.html
Now I want to use a pre-compiled .so file and cannot figure out where to put it so my code will be able to access it.
so, i created a folder at framewaork/base/libs/my_folder/
and put there two files:
my_lib.so
android.mk
the content of the android.mk is :
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= my_lib
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
the make ran without errors, but when the code tried to load the library via:
System.loadLibrary("my_lib");
i got this error:
06-27 13:58:55.581: E/AndroidRuntime(806): Caused by: java.lang.UnsatisfiedLinkError: Library my_lib not found; tried [/vendor/lib/my_lib.so, /system/lib/my_lib.so]
so i added the so file to out/target/product/generic/system/lib
but got the same error.
so where should i place the my_lib.so file ? and is an android.mk needed for it ?
maybe i should register it somewhere on the system ?
Thanks in advance!
So the answer was quite simple.
I really need to copy my lib to the system image, to the system/lib folder, because the make command doesn't copy it from out/target/product/generic/system/lib to system.img
the trick is to add this line
PRODUCT_COPY_FILES += $(LOCAL_PATH)/my_lib.so:system/lib/my_lib.so
to full.mk file. it's location is:
android-source/build/target/product
also put the my_lib.so near it
(as seen by the path)
if you are planning to run the image on a real device, add this line after the device name definition.
f.ex. if you are running on Nexus 4, put it at android-source/device/lge/mako/full_mako.mk
You can add your prebuilt library in Android AOSP source code and it be a part of your AOSP System Image. I am describing step by step procedure for it.
Step 1 Create a folder ( let say myLibs) inside external folder of AOSP source code.
external folder of AOSP source code refers to external open source libraries.
That means libraries that the Android platform depend upon but that are not primarily developed and maintained by the Android open source project.
examples are webkit for the browser, FreeType for fonts, SqlLite for databases and so on. As more features are added to Android, more of these libraries are included in external.
Step 2 Create a Android.mk file
Create a Android.mk file inside your folder(let say myLibs) and copy your .so file in it.
You can use following content for your android.mk file
# Prebuilt Lib
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libMyabc # your lib name
LOCAL_SRC_FILES := libMyabc.so
# your lib .so file name
include $(BUILD_SHARED_LIBRARY)
Step 3 Add your library in Framework
In final step you have to add your library in Android AOSP framework makefile so that it will recognise and build as a part of System image.
You find Framework Android.mk file on following location
/android_aosp_sourcecode_download_folder/framenter code hereeworks/base/core/jni/
Open Android.mk file and add your library in following section
LOCAL_SHARED_LIBRARIES := \
You can put your library name in that section example libMyabc \
That's it... now make it (make -j4) and you find your added so file in following folder
/android_aosp_sourcecode_download_folder/out/target/product/generic/obj/lib
with file name like :- libMyabc.so and libMyabc.so.toc
and you also found it in system/lib folder
/android_aosp_sourcecode_download_folder/out/target/product/system/lib
in my case, solved this problem by creating Android.bp file in the repo where i put my prebuilt libraries, then i added them as product packages in the product mk file. this is an example :
Android.bp :
cc_prebuilt_library {
name: "product_package_name_in_MK_file",
relative_install_path: "sub_lib/sub_sub_lib",
stem: "output_file_name", // .so will be added automatically to out file name.
compile_multilib: "both",
multilib: {
lib32: {
srcs: ["path for src 32bit lib"],
},
lib64: {
srcs: ["path for src 64bit lib"],
},
},
strip: {
none:true,
},
allow_undefined_symbols: true,
check_elf_files: false,
vendor: true,
enabled: true,
}
product_mk file :
...
PRODUCT_PACKAGES += product_package_name_in_MK_file
...

Linker trouble when using LuaJIT prebuilt static library with android under cygwin

I think I spent most of yesterday unsuccessfully wrestling with this, any help would greatly appreciated and make me extremely happy! Even a next step to try to find the root of the issue is something I'm stuck on at the moment!
I have an Android 2.2 project that's trying to reference a prebuilt LuaJIT static library but ndk-build gives me this error:
test_android.cpp:25: undefined reference to `luaL_newstate'
I built LuaJIT as liblua.a, I've placed that in the root of my JNI directory with the relevant headers. I've have one Android.mk as shown below:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := lua
LOCAL_SRC_FILES := liblua.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := test_android.cpp
LOCAL_LDLIBS := -llog -lGLESv2
LOCAL_STATIC_LIBRARIES := lua
include $(BUILD_SHARED_LIBRARY)
In test_andrdoid.cpp I've got this code:
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
void test()
{
lua_State* lua = lua_open();
}
This seems like a linker error, for some reason the static library file is not being correctly referenced. But, to me, the makefile seems correct.
Any help would be greatly appreciated!
To start with: is there anyway to see how everything is being linked
together and if my shared library module is really get access
to the static library?
Additional Information
Here's extra information that I think could be relevant!
Building the library
Maybe it's the static lib file that's not correct? (Is there anywhere I could download a prebuilt one to check?). I made it with this script (from the LuaJIT website). I'm using the latest stable LuaJIT, 1.1.8
NDK=/cygdrive/c/android-ndk-r8b
NDKABI=8
NDKVER=$NDK/toolchains/arm-linux-androideabi-4.4.3
NDKP=$NDKVER/prebuilt/linux-x86/bin/arm-linux-androideabi-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
make linux HOST_CC="gcc -m32" CROSS=$NDKP TARGET_FLAGS="$NDKF"
This builds fine and creates a liblua.a in the /src/ directory. (I ran nm on it and it lists out all the function prototypes I'd expect). I don't know if there's anything else I can do to ensure it's really a build for ARM?
NDKABI=8 means I'm targeting Android 2.2
Setting up the test Android Project
I create a brand new 2.2 android project using this command:
android create project --target 3 --name test --path . --activity TestActivity --package com.test
Target 3 maps to Android 2.2 on my system (using android list devices).
I create the jni folder and have a test_android.h and test_android.cpp. Then I use ndk-build to build them - which works fine when I'm not trying to reference LuaJIT. When I do try and use Lua I get the following error:
Full Error Message
Cygwin : Generating dependency file converter script
Compile++ thumb : test <= test_android.cpp
In file included from jni/test_android.h:3:0, from jni/test_android.cpp:2:
C:/android-ndk-r8b/platforms/android-8/arch-arm/usr/include/jni.h:592:13: note:
the mangling of 'va_list' has changed in GCC 4.4
Prebuilt : liblua.a <= jni/
StaticLibrary : libstdc++.a
SharedLibrary : libtest.so
obj/local/armeabi/objs/test/test_android.o: In function `test()':
C:\Users\Grrr\Documents\mycode\static_lib_test/jni/test_android.cpp:25: undefined reference to `luaL_newstate'
collect2: ld returned 1 exit status
/cygdrive/c/android-ndk-r8b/build/core/build-binary.mk:378: recipe for target `obj/local/armeabi/libtest.so' failed make: *** [obj/local/armeabi/libtest.so] Error 1
Most of the issues I've seen searching around are due to the local library include order, as I only have one library this shouldn't be an issue and suggests I've managed to get something more fundamental wrong :)
Update
I've since built normal Lua and added that as prebuilt static library and it works fine. I suspect its how I've built LuaJIT but I'm not sure how to correctly build it, or find a working prebuilt version.
The linking for this was fine, or at least the makefile was.
The problem was the LuaJIT library wasn't built for ARM (I used objdump -a lualib.a, to check this). I downloaded the latest LuaJIT, ran the script under linux and got an ARM library. Everything links nicely now!

android using external shared library

I am facing issues in using an external shared library in my Android application. I created an Android.mk file as given below:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyApp
LOCAL_SRC_FILES := myexternallib.so
include $(PREBUILT_SHARED_LIBRARY)
Using ndk-build I am able to generate a local native library and I use this native library in my System.loadLibrary method.
When I run the application I get an error java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1486]: 2659 unknown reloc type 19 # ( 4220)
On further search I found a link which recommends to build the shared library using the android toolchain. So I used one of the toolchain arm-eabi-gcc, which is available in the prebuilt/linux_x86/toolchain/arm-eabi-4.4.3/bin directory of the android source code, to build my source files. I get an error arm-eabi-gcc: error trying to exec 'cc1': execvp: No such file or directory. I also noticed that the toolchain folder does not have a file named cc1.
Am I following the right procedure? Is there some other way to reference external shared library in Android code?
It is true that you should use Android toolchain.
Android NDK comes with detailed instructions on using its toolcahin: http://source-android.frandroid.com/ndk/docs/STANDALONE-TOOLCHAIN.html. If you have specific questions about this document, feel free to ask.

SharedLib dependency # Mixed mode APK

I am building a mixed mode Android project, the project is using the native ffmpeg
The Libs are
2.1. libavutil.so -> libavutil.so.51
2.2. libavcodec.so -> libavcodec.so.54
2.3. libavformat.so -> libavformat.so.54
My Java code include the following JNI section to load the native libs:
static {
     System.loadLibrary("avutil");
     System.loadLibrary("avcodec");
     System.loadLibrary("avformat");
}
'libavcodec.so' depends on 'libavutil.so.51' AND NOT on 'libavutil.so'.
When running my activity  System.loadLibrary("avcodec"); excepts with "could not load needed library 'libavutil.so.51' for 'libavcodec.so' (Library 'libavutil.so.51' not found)"
On my Android.mk I have the following section to have the native libs added to the APK:
include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := ../../../mylib/libmylib.so
include $(PREBUILT_SHARED_LIBRARY)
replacing libmylib.so with libmylib.so.%some number% cause the build to fail with [LOCAL_SRC_FILES should point to a file ending with ".so"]
Having the above in mind, how can I have libavcodec loading w/o the dependency problem ?
Can I fix libavcodec.so dependency to point to libavutil.so and not to libavutil.so.51 ?
Can I change Android.mk so it will be able to pack libavutil.so.51 ( non .SO extention ) ? will it then be loadable using 'System.loadLibrary' ?.
Any help will be appreciated!!!
Nadav at Sophin
Work-around was simply to use the static libs rather than the dynamic libs, this however, is a temporary work-around as due to LGPL limitations the SharedLibs are mandatory for commercial use.

Categories

Resources