Hi I am trying to port an OpenGL desktop app to android. I have no knowledge of android development so am depending on Qt Creator to package the app. As part of the setup, I have invoked 'make-standalone-toolchain' script in android ndk with following settings
--platform=android-21
--toolchain=arm-linux-androideabi-4.9
--system=linux-x86_64
Then I used android-cmake and passed it the path of my newly created standalone-toolchain, which created libassimp.so, libassimp.so.3, and libassimp.so.3.1.1(ln) inside my assimp directory tree.
I passed the libassimp.so path to Qt creator project build menu under 'additional libraries'. However, on deploying the app on android, it crashes with error:
dlopen("/data/app/org.qtproject.example.a3dqtquick-2/lib/arm/lib3dqtquick.so", RTLD_LAZY) failed: dlopen failed: could not load library "libassimp.so.3" needed by "lib3dqtquick.so"; caused by library "libassimp.so.3" not found
I can even see the libassimp.so (not libassimp.so.3) file inside the project build directory at
../android-build/libs/armeabi-v7a.
Not sure where to go from here, manually placing libassimp.so.3 at this location does not sort out the problem. Thanks for reading. I will add further info on your feedback . please forgive any info deficiency as this is my first experiment with android.
Following is the deployment-settings.json file
"description": "This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.",
"qt": "/home/ubashir/programs/Qt/5.4/android_armv7",
"sdk": "/home/ubashir/programs/android-sdk-linux",
"sdkBuildToolsRevision": "21.1.2",
"ndk": "/home/ubashir/programs/android-ndk-r10d",
"toolchain-prefix": "arm-linux-androideabi",
"tool-prefix": "arm-linux-androideabi",
"toolchain-version": "4.9",
"ndk-host": "linux-x86_64",
"target-architecture": "armeabi-v7a",
"qml-root-path": "/home/ubashir/code/3dqtquick",
"application-binary": "/home/ubashir/code/3dqtquickAndroid/lib3dqtquick.so"
UPDATE:
I have now tried this.. replace all links to assimp.so.3.1.1 with copies of the latter so now my library libassimp.so.3 is a file instead of link to libassimp.so.3.1.1. I manually added libassimp.so.3 to my project subfolder android/libs/aremabi-v71 --- no good. I confirm that my build directory shows all libassimp files as I manually added them so presumably they are being deployed but the error remains :
failed: dlopen failed: could not load library "libassimp.so.3" needed by "lib3dqtquick.so".
As outlined here http://webmail.dev411.com/p/gg/android-ndk/1386vger6e/use-assimp-c-library-in-ndk-ld-error-obj-local-armeabi-v7a-libassimp-so-incompatible-target-for-use-with-vuforia
I even edited the link.txt file after running cmake on my assimp build directory for android, altering the entry -soname,libassimp.so.3 with -soname,libassimp.so but it still creates libassimp.so.3.1.1 with its two links , i.e., libassimp.so.3 and libassimp.so. So still stuck..
I ran into the same problem with a shared library I built with CMake for and Android project. I found a way to fix it. There might be a cleaner solution if you were more familiar with CMake.
Search through the CMakeLists.txt file(s) for "SOVERSION" and "SET_TARGET_PROPERTIES()"
In the SET_TARGET_PROPERTIES() routine comment out the lines for VERSION and SOVERSION as follows
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES # create *nix style library versions + symbolic links
DEFINE_SYMBOL DSO_EXPORTS
# VERSION ${PROJECT_VERSION}
# SOVERSION ${PROJECT_SOVERSION}
CLEAN_DIRECT_OUTPUT 1 # allow creating static and shared libs without conflicts
OUTPUT_NAME "${PROJECT_NAME}${PROJECT_DLLVERSION}" # avoid conflicts between library and binary target names
)
Then rerun the configure and generate steps in CMake and rebuild the target. This should give you a .so without any version numbers.
I'll suggest you to take a look at the solution I've found to my problem (that is very similar to yours):
libgdal.so android error: could not load library "libgdal.so.1"
Hope this helps.
Related
I am very new to android and here is what I want to do:
I have some cpp files and want to create so file which will be later used in another android project. Now, I tried with cmake and using linux native libs like libc, libpng, libjepeg etc. But when I used that so file in the other android project, I got linker errors like unsatisfied liker error libc etc.
java.lang.UnsatisfiedLinkError: dlopen failed: library "libc.so.6" not found
Here are the details of files I have:
there is a file color.cpp which used libpng and libjpeg, and color.h
there is another file which uses jasper lib.
and one last file which has all the api's (public head file).
I am combining all this into an so.
I think I have to create so file with android ndk custom toolchain, for it work. I am very new to this android ndk and have no idea how to create so file.
Can you please help?
Also, I have dependencies of libs like libjepeg, libpng, jasper, libc, I am not sure weather those are available in android toolchain or they is any way to add those.
Thank you in advance.
I am currently working on a project regarding neural networks.
For this, I want to build an Android Application which should use tensorflow [lite] to solve some object detection / recognition problems.
As I want the code to be as portable as possible, I want to write most of the code in C++, thus using the C++ API of tensorflow lite over the Java API / wrapper.
So, I modified tensorflow/contrib/lite/BUILD and added the following to be able to create a shared tensorflow library.
cc_binary(
name = "libtensorflowLite.so",
linkopts=["-shared", "-Wl"],
linkshared=1,
copts = tflite_copts(),
deps = [
":framework",
"//tensorflow/contrib/lite/kernels:builtin_ops",
],
)
(Which is based on the answer to this issue: https://github.com/tensorflow/tensorflow/issues/17826)
Then I used
bazel build //tensorflow/contrib/lite:libtensorflowLite.so --crosstool_top=//external:android/crosstool --cpu=arm64-v8a --host_crosstool_top=#bazel_tools//tools/cpp:toolchain --cxxopt="-std=c++11"
to finally build it.
Afterwards I headed over to Android Studio and set up a basic project.
For adding the shared library to the project, I refered to this example:
https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs
I also added the needed dependencies for flatbuffers.
The build / compilation process succeeds without any linker errors (well, at least after trying around for some hours..).
The APK is then successfully installed on an Android device, but immediately crashes after it starts. Logcat gives the following output:
04-14 20:09:59.084 9623-9623/com.example.hellolibs E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.hellolibs, PID: 9623
java.lang.UnsatisfiedLinkError: dlopen failed: library "/home/User/tensorflowtest/app/src/main/cpp/../../../../distribution/tensorflow/lib/x86/libtensorflowLite.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1657)
at com.example.hellolibs.MainActivity.<clinit>(MainActivity.java:36)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1174)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
I tried this on an android x86 emulator and on a real arm64-v8a android smartphone.
So for me this looks like on startup the application tries to load the tensorflowLite shared library, but is unable to find it.
Opening the apk with a zip archive manager I can verify that the platform (arm, x86) dependent .so files are packed into the APK as expected (by adding the following to build.gradle:
sourceSets {
main {
// let gradle pack the shared library into apk
jniLibs.srcDirs = ['../distribution/tensorflow/lib']
}
})
What I do not understand is why it looks for the library in the path where I placed it on my Ubuntu 17.10 PC.
So, I thought I had done a mistake trying to adapt the example about adding external libraries to an Android Studio Project I mentioned earlier.
That's why I downloaded the whole project and opened it in Android Studio and verified that the example works as expected. Afterwards I replaced the example libgperf.so by the libtensorflowLite.so and left everything else, especially the CMakeLists.txt, untouched.
But I get the exact same error again, therefore I suspect this to be a problem with the libtensorflowLite library itself and not the android project (although that's just my guess).
I am working on android studio 3.1.1, NDK Version 14 and API Level 24 (Android 7.0).
If anyone has an idea what could be wrong, any help would be highly appreciated.
I am also open for any other methods which allow me to use tensorflow lite with C++ for an android application.
Thanks a lot,
Martin
I just remembered I asked this question a few weeks ago.
Meanwhile, I found a solution to the problem and TensorflowLite is now nicely embedded into my Android Project, where I do all the programming using the C++ API!
The problem was that the Tensorflow shared library I built did not contain a soname. So, during build process, the library was stripped and as no name was found, the path was used as the "name". I noticed that while I further investigated my native-lib.so (the NDK C++ library which is then loaded by the App) using linux "strings" tool. Here I found out that indeed the path to load the library from "/home/User/tensorflowtest/app/src/main/cpp/../../../../distribution/tensorflow/lib/x86/libtensorflowLite.so" was set.
Adding a "-Wl,-soname=libtensorflowLite.so" to the build options in the BUILD file fixed this issue! You can find the whole rule I used below.
As it was a pain to get everything set up due to the lack of explanations (it seems TensorflowLite is mostly used via Java API on Android ?), I want to give a short guidance on how use the C++ API of TensorflowLite in Android Studio (from within an Android NDK project).
1. Build the library for your architecture
To use the C++ API, you first need to build the TensorflowLite library. For this, add the following rule to the BUILD file in tensorflow/contrib/lite:
cc_binary(
name = "libtensorflowLite.so",
linkopts=[
"-shared",
"-Wl,-soname=libtensorflowLite.so",
],
linkshared = 1,
copts = tflite_copts(),
deps = [
":framework",
"//tensorflow/contrib/lite/kernels:builtin_ops",
],
)
Note: With this, a shared library can be built! A static one might also work.
Now you can build the library using
bazel build //tensorflow/contrib/lite:libtensorflowLite.so --crosstool_top=//external:android/crosstool --cpu=arm64-v8a --host_crosstool_top=#bazel_tools//tools/cpp:toolchain --cxxopt="-std=c++11"
If you want to support multiple architectures, you will have to build the library several times and change the --cpu flag correspondingly.
NOTE: This works fine at least for arm64-v8a and the armeabi-v7a (haven't tested it with MIPS so this might work aswell). However on an x86 device, I get the "atomic_store_8" error already adressed in this topic: https://github.com/tensorflow/tensorflow/issues/16589
2. Add the library and the needed headers to be included in your Android Studio project
Having built the library, you now need to make sure it also is linked into your Application (more specifically: Into your Android NDK library, which in my case is named "native-lib"). I will give a short overview on how to do this, however if you need a more detailed explanation you may refer to the github link I provided in my initial question: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs
2.1. In your Android Studio Project, open the CMakeLists.txt
2.2. Add the following:
# This will create a new "variable" holding the path to a directory
# where we will put our library and header files.
# Change this to your needs
set(distribution_DIR ${CMAKE_SOURCE_DIR}/distribution)
# This states that there exists a shared library called libtensorflowLite
# which will be imported (means it is not built with the rest of the project!)
add_library(libtensorflowLite SHARED IMPORTED)
# This indicates where the libtensorflowLite.so for each architecture is found relative to our distribution directory
set_target_properties(libtensorflowLite PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/lib/${ANDROID_ABI}/libtensorflowLite.so)
# This indicates where the header files are found relative to our distribution dir
target_include_directories(native-lib PRIVATE
${distribution_DIR}/include)
# Finally, we make sure our libtensorflowLite.so is linked to our native-lib and loaded during runtime
target_link_libraries( # Specifies the target library.
native-lib
libtensorflowLite
# Links the target library to the log library
# included in the NDK.
${log-lib} )
2.3. Open the build.gradle for your Module: App (not the project one!)
2.4. Make sure our library will be packed into your APK
Add this inside the Android section:
sourceSets {
main {
// let gradle pack the shared library into apk
jni.srcDirs = []
jniLibs.srcDirs = ['distribution/lib']
}
}
You may have to edit the path accoding to your needs: The files here will be packed in to your .apk inside the lib directory.
3. Include flatbuffers
TensorflowLite uses the flatbuffers serialization library. I guess this will be added automatically if you build your project using bazel. But this is not the case when using Android Studio.
Of course, you could also add a static or shared library too.
However, for me it was easiest to just let flatbuffers compile each time with the rest of my app (it is not that big).
I copied all of the flatbuffers *.cpp source files to my project and added them to the CMakeLists.
4. Copy the needed headers for TensorflowLite and flatbuffers
In 3. I just copied the cpp files to my project.
However, the header files need to be located in the directory we set in target_include_directories in step 2.2.
So go ahead and copy all of the flatbuffers (from the flatbuffers repository) *.h files to this directory.
Next, from the TensorflowLite repository, you need all header files inside the tensorflow/contrib/lite directory. However you should keep the folder structure
For me it looks like this:
distribution
lib
arm64-v8a
libtensorflowLite
armeabi-v7a
libtensorflowLite
include
flatbuffers
tensorflow
contrib
lite
kernels
nnapi
schema
tools
So, if I haven't forgotten anything everything should be set up correctly by now!
Hopefully this helped and it worked for you as it did for me ;)
Best regards,
Martin
I'm trying to load shared libraries in Unity. It works on Windows/Editor but not on Android, whatever I do or use for libraries I always get the DllNotFoundException.
I am using lib.so files, those are for 32BIT ARM EABIS, so the cross platform compilation seems to succeed.
my lib.so files are in the Assets/Plugins/Android/libs/armeabis-v7a/ folder.
I tried different syntax for DllImport (assuming the lib is called Plugin, and the files Plugin.dll and libPlugin.so) :
[DllImport("Plugin")] => works for Windows only
[DllImport("libPlugin.so")] => obviously wont work for Windows, but doesn't work for Android either.
If I open the .apk with winrar, libs are in the libs/armeabis-v7a folder.
The smartphone I use for my tests is an OnPlus3 with a armv8 processor.
Anyone managed to sucessfuly load a shared native library on Android ? Any ideas about what I'm doing wrong ?
Thank you
EDIT:
plugin code can be found here : https://github.com/FFmpeg/FFmpeg
C# code can be found here : https://github.com/Ruslan-B/FFmpeg.AutoGen/blob/7e001dde3acaad70ed188b75e686f23574f81388/FFmpeg.AutoGen/FFmpegInvoke.cs
Adding FFmpegInvoke.cs in the Unity Project or generating the FFmpeg.Autogen.dll and adding it to the project gives the same result (dll just makes the Unity Project faster to build).
I noticed few things you are doing wrong:
my lib.so files are in the Asset/Plugins/libs/armeabis-v7a/ folder.
That should be at:
Assets/Plugins/Android/libs/armeabi-v7a
If you have the x86 architecture version of the plugin,you should place them at:
Assets/Plugins/Android/libs/x86
I tried different syntax for DllImport (assuming the lib is called
Plugin, and the files Plugin.dll and libPlugin.so) :
None of those are correct. If the plugin file name is "libPlugin.so", you should use "Plugin" as the name.
Do not include the lib prefix.
Do not include the ".so" postfix.
Again, if the plugin name is "libVideoPlayer.so", you have to use "VideoPlayer". The "lib" and ".so" are removed. Nothing else will work.
One final note for you, for Android C++ plugin, you do not need to export the plugin. For example, DLLExport __declspec(dllexport) is not necessary.
Although, you must put the function name inside "extern "C""
My problem is the following: I have succesfully built GDAL 1.10.1 using an Android toolchain (CC=i686-linux-android-gcc, CXX=i686-linux-android-c++) that produces the following output libraries libgdal.a, libgdal.la, libgdal.lai, libgdal.so, libgdal.so.1, libgdal.so.1.17.1 in the output folder .libs (in the following I'll call this folder $GDAL_LIB_PATH).
I am trying to build a simple Android app (a simple widget application with a QPushButton named TestAndroid) using Qt 5.4 on Windows. If I don't use GDAL everything works fine and I am able to run my app on an Android emulator for all available platforms: x86, armeabi and armeabi-v7.
Nonetheless, if I try to use GDAL (ex. by simply calling GDALAllRegister() in the initialization of the app) and then linking to libgdal.so the application crashes with the following error:
E/art ( 1614):
dlopen("/data/app/org.qtproject.example.TestAndroid-1/lib/x86/libTestAndroid.so",
RTLD_LAZY) failed: dlopen failed: could not load library
"libgdal.so.1" needed by "libTestAndroid.so"; caused by library
"libgdal.so.1" not found
I have verified that the Android platform is the right one (x86), otherwise the linker would skip the wrong libgdal.so object.
I have included libgdal.so in the *.apk (generated by Qt) using ANDROID_EXTRA_LIBS *= $GDAL_LIB_PATH/libgdal.so. The other files libgdal.so.x.x cannot be included in the same way since Qt prevents it.
In order to avoid dynamic linking I have also tried to link my app with libgdal.a but many link-time errors appears (ex. undefined reference to 'atof')
I have searched on the web but I have not found a solution to my problem.
I am not constrained to use dynamic linking so, a solution to any of the following problems is good for me:
Is there a way to avoid the creation of libgdal.so.x.x files when building GDAL ?
Is there a way to include libgdal.so.x.x files in the *.apk file generated by Qt ?
How can I avoid link-time errors when linking the static library libgdal.a ?
Thanks in advance for any reply!
After several days of trials and errors (mainly errors) I have found a solution to my problem.
I'm writing it as an answer to my question so that it may be helpful to others.
The problem was during the link-time of GDAL. Briefly: the linker created the "real name" shared library libgdal.so.1.17.1 together with the links to it libgdal.so.1 and libgdal.so.
For some reasons (which I ignore) forcing the link to libgdal.so, the linker searches for libgdal.so.1 (which, in turn, would have searched for libgdal.so.1.17.1).
The workaround that solved my problem can be summarized in the following steps:
In the GDAL root, run the ./configure according to the desired configuration (see http://trac.osgeo.org/gdal/wiki/BuildingForAndroid) checking that libtool is ENABLED
Edit the created libtool file (e. g. with gedit) as follows:
replace the value of library_names_spec with library_names_spec="\$libname\${shared_ext}"
replace the value of soname_spec with soname_spec=""
Type make
In the output folder .libs/ the only libgdal.so will be created and now the link to libgdal.so seems to work fine.
I want to make some changes to LatinIME. I got the code from git repository-
git clone https://android.googlesource.com/platform/packages/inputmethods/LatinIME
But I don't know how to build the apk file from the code. If anyone has build the LatinIME from the code, can you please share instructions.
Specifically I want to know how to build the dictionary tools (I guess I would need ndk), how to build the native code (again I guess it would required ndk) and finally how to build the java code by using the lib file from native code.
I tried creating Android app project in eclipse (using existing code option) by giving root directory as LatinIME/java I was able to compile but since it didn't have libjni_latinime.so, it crashed. I then got the .so file from emulator and put it in the libs/armeabi-v7a folder. Now I get this exception:
10-15 12:54:55.289: E/AndroidRuntime(32253): FATAL EXCEPTION: InitializeBinaryDictionary
10-15 12:54:55.289: E/AndroidRuntime(32253): android.content.res.Resources$NotFoundException: File res/raw/main_en.dict from drawable resource ID #0x7f070003
I think I may have solved this...
Having encountered a similar problem in another project where resources were being unnecessarily compressed due to their file extension I renamed the dictionaries (.dict) to .jet - an extension excluded from compression. Voila, dictionaries are now working. Not sure how good of a resolution that is seeing as the dictionaries are now uncompressed but it's a step in the right direction at least?
So far i have customised the LatinIME many times for different projects. I never faced this problem.
But i never used eclipse to create apks. I downloaded whole AOSP code onto my machine and compiled the modified source with AOSP. And mm creates the apk file in out folder, and can be installed with adb install -r latinime.apk
Here is how to download AOSP :http://source.android.com/source/downloading.html
And here is how to compile it initially : http://source.android.com/source/initializing.html and http://xda-university.com/as-a-developer/getting-started-building-android-from-source
And the LatinIME can be found in <android roo>/packages/inputmethods/LatinIME, Modify the code ther and cd to the same path and run mm (you need to do source build/envisetup.sh and lunch full-eng done in same terminal before doing mm)
First some background. As also suggested by the other answer issue seems to be related of .dict files being compressed. For example you can see how official Android builds solve this in project's tests for LatinIME
# Do not compress dictionary files to mmap dict data runtime
LOCAL_AAPT_FLAGS += -0 .dict
A quick searching the web reveals that to day this kind of directive or instructing aapt from Eclipse isn't trivial. You would probably end up creating a build.xml in case you want to handle don't-compress-dicts case properly.
One nice suggestion is this answer/question on how to instruct aapt to not to compress certain files.
If you want to build this from official git link you provide, you'll end up building whole Android repo, which you can by following building-running instructions.
If using gradle, add this
android {
aaptOptions {
noCompress 'dict'
}