I'm trying to build Tensorflow lite with C++ natively on Android device. I've built a .So file of tensorflow for every architecture and placed into the jniLibs folder. This is my Cmake file:
set(pathToProject /ih/user/project/NativeTfLite/app)
set(libs ${pathToProject}/src/main/jniLibs)
add_library(libtensorflowLite SHARED IMPORTED
)
set_target_properties(libtensorflowLite PROPERTIES IMPORTED_LOCATION
${libs}/${ANDROID_ABI}/libtensorflowLite.so)
find_library(
log-lib
log )
add_library(
native-lib
SHARED
native-lib.cpp)
target_include_directories(native-lib PRIVATE
${lib}/include)
target_link_libraries( # Specifies the target library.
native-lib. #Problem is here when linking native-lib with libtensorflowlite
libtensorflowLite
${log-lib} )
During compile time these files are found. However in target_link_libraries line, the linking of the 2 libraries libtensorflowlite and native-lib there is a runtime crash with the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library "/Users/ih/project/cameraFrames/NativeTfLite/app/src/main/jniLibs/arm64-v8a/libtensorflowLite.so" not found
Additionally the .SO files are not linked to the APK.
Here is my build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.proj.nativetflite"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
sourceSets {
main {
jniLibs.srcDir 'src/main/jniLibs'
jniLibs.srcDirs = ["src/main/jniLibs"]
}
}
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments '-DCMAKE_VERBOSE_MAKEFILE=ON'
}
}
ndk {
abiFilters "armeabi-v7a", "x86" , "arm64-v8a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
dependencies {
implementation fileTree(dir: 'jniLibs', include: '**/*.so')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
What is causing this?
Prior to AGP 4.0 you need to explicitly package prebuilt libraries with jniLibs: https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs. Note that the docs say you don't need to do this for anything declared by CMake, but I'm fairly certain the docs are wrong here (I've reached out to the doc owner to see if we need to fix that or not, since it is correct for 4.0).
This should be unnecessary in 4.0, but that hasn't reached stable yet.
Although I think Dan Albert's answer should be accepted, I'd like to add that I got the exact same error because I had not set the correct path to my tflite lib.
I kept my .so files in src/main/cpp/tflite/lib/${ANDROID_ABI}/, so in build.gradle I needed to add:
main {
jniLibs.srcDirs = ['src/main/cpp/tflite/lib']
}
also, it could be worth checking out this answer (also from Dan) regarding making sure the SONAME of the .so is correct.
Related
I'm developing an Android application for simple Facial recognition.
My Application build and run fine in emulator,
But App can't install in real device,
And we get Gradle error for CMake related task, with error-message:
Task :engine:configureCMakeDebug[arm64-v8a] FAILED
Execution failed for task ':engine:configureCMakeDebug[arm64-v8a]'.
[CXX1410] D:\KAM\code\AET\AET\engine.cxx\Debug\3p465u2i\arm64-v8a\android_gradle_build.json debug|arm64-v8a : expected buildTargetsCommandComponents or ncnn-release-arm64-v8a.buildCommandComponents to exist
CMakeList.txt:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_BUILD_TYPE "release")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../../distribution/${ANDROID_ABI})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(ncnn STATIC IMPORTED)
set_target_properties(ncnn PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libncnn.a)
add_library(opencv_core STATIC IMPORTED)
set_target_properties(opencv_core PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_core.so)
add_library(opencv_imgproc STATIC IMPORTED)
set_target_properties(opencv_imgproc PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_imgproc.so)
add_library(opencv_codecs STATIC IMPORTED)
set_target_properties(opencv_codecs PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_imgcodecs.so)
file(GLOB jni_srcs
"*.cpp"
"detection/*.cpp"
"live/*.cpp"
)
add_library(engine SHARED ${jni_srcs})
target_link_libraries(engine log jnigraphics ncnn opencv_core opencv_imgproc opencv_codecs android -static-openmp -fopenmp)
build.gradle(Module: engine):
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 28
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
abiFilters 'arm64-v8a'
arguments "-DANDROID_ARM_NEON=TRUE"
arguments "-DANDROID_TOOLCHAIN=clang"
}
}
}
packagingOptions {
pickFirst '**/*.so'
}
externalNativeBuild {
cmake {
version = "3.6.0"
path "src/main/cpp/CMakeLists.txt"
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
ndkVersion '22.1.7171670'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.2'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
I try to find the reason but no luck. So far find only [this][1].
Any help or resource will be great for me. Thanks
I just met similar "expected buildTargetsCommandComponents ..." error log.
And like many other times, deleting the build directory and restarting IDE fixed the issue.
first rebuild your app and then check this location
PROJECT PATH...\app\build\intermediates\cmake\debug\obj
There should be at least 4 folders for different abi's
x86 - x64 -- arm64/v7a -- arm64/v8
if its not exist there
apply this to your build.gradle
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
I would like to know how to build my APK so that my libraries are installed/copied under /data/data/<package name>/lib when installing the APK.
I am using Android Studio 4.0.1
I build an APK and confirm when I extract it that I have a
lib/arm64-v8a folder that contains my jni libs.
I want that after I install my APK, some other applications on the same device can access the libs that I have in the lib/arm64-v8a. The /data/data/<package name> folder seems to be the right place for this, hence my question; if there is another approach for making my libraries accessible on device, I am open to it.
I set android.bundle.enableUncompressedNativeLibs=false
in my gradle.properties file based on this discussion even
though I didn't see any effect using it with true or false.
I set android:extractNativeLibs="true" in my Manifest
However, when I adb install my apk, the /data/data/<package name>/ folder on my device only contains a cache and code_cache folder, both of which are empty.
I do see under /data/app/ a folder with my libraries but they include strings that are randomly set each time I install the APK:
/data/app/~~sFE8-eNknFAkhKJ-1S03lg==/<package name>-rsDLNgpi4vult7yVBrPNOQ==/
base.apk
lib/arm64/
<my .so in there>
These random strings prevent me from accessing reliably my libraries from any other application. (If there is a way to not have these random strings as part of the name and /data/app is the recommended location for my libraries to be shared with other applications, I am interested in that alternate approach.)
I have also installed other prebuilt APK and with these, I do see the libraries under /data/data/<package name>/lib like I want. This to me indicates that my issue is related to how I build my APK with AS 4.0.1, not to my device, its Android version, or how I install the APK.
Here is my gradle file:
import java.util.regex.Matcher
import java.util.regex.Pattern
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
lintOptions {
checkReleaseBuilds false
abortOnError false
}
sourceSets.main {
jniLibs.srcDirs = ['libs']
jni.srcDirs = []
}
defaultConfig {
applicationId "com.example.myexample"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
version "3.17.0"
cppFlags ""
arguments "-DANDROID_STL=c++_shared"
}
}
ndk {
moduleName "myexample"
abiFilter "arm64-v8a"
ldLibs "log"
}
packagingOptions {
exclude "lib/arm64-v8a/libassets.so"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
version "3.17.0"
path "src/main/cpp/CMakeLists.txt"
// There can be only one CMAKE per project: https://developer.android.com/studio/projects/gradle-external-native-builds
}
}
}
task copyFiles(type: Copy) {
description = 'Testing a manual copy operation (confirmed it works)...'
from file("../dsp/external/ship/libmyexample_skel.so")
into file("$buildDir/res/raw/")
}
project.afterEvaluate {
preBuild.dependsOn copyFiles
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
Something else I tried: I created manually a src/main/jniLibs.arm64-v8a folder in which I place a .so. That .so appears in the my apk when I extract it, but my /data/data/<package name>/ folder doesn't have a lib nevertheless.
I think you need to add this code to add libs in the appropriate folder like /data/data/<package name>/lib
add this to app's build.gradle file into android{} tag
sourceSets.main {
jniLibs.srcDirs = ['libs']
jni.srcDirs = []
}
this to CMakeList.txt file
cmake_minimum_required(VERSION 3.4.1)
find_library( # Sets the name of the path variable.
log-lib
log)
set(distribution_DIR ${CMAKE_SOURCE_DIR}/libs)
add_library(yourLibName
SHARED
...//list of your c/c++ files here from jni folder
)
target_link_libraries(yourLibName ${log-lib})
as per developer.android.com
Note: When making changes to the Gradle configuration, make sure to
apply your changes by clicking Sync Project in the toolbar.
Additionally, when making changes to your CMake or ndk-build script
file after you have already linked it to Gradle, you should sync
Android Studio with your changes by selecting Build > Refresh Linked
C++ Projects from the menu bar.
I'm trying to implement yctung's AndroidLibSvm into my project with Android Studio 3.2.1. While the app works fine on any emulated device (I tried Android 23 and 28, both worked flawlessly), it crashes on my real device (a lenovo tablet with Android 6.0) with the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy" referenced by "/data/app/com.krautkremer.nils.mymirror-2/lib/arm/libjnilibsvm.so"
as soon as the app tries to run the part of the code that uses cytung's lib.
There are a few similar cases on SO e.g. here or here but setting my
arguments "-DANDROID_PLATFORM=android-23"
or any other android-x and my targetSdkVersion to 23 in the build.gradle didn't solve it.
this is my build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.krautkremer.nils.mymirror"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
arguments "-DANDROID_PLATFORM=android-23"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
//exclude 'META-INF/proguard/androidx-annotations.pro'
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
implementation 'androidx.media:media:1.1.0-alpha01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
implementation 'com.google.android.material:material:1.1.0-alpha01'
implementation 'androidx.annotation:annotation:1.0.1'
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.google.firebase:firebase-ml-vision:18.0.2'
implementation 'com.google.firebase:firebase-ml-common:16.1.6'
implementation 'com.google.firebase:firebase-ml-vision-face-model:17.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1-alpha01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1-alpha01'
implementation project(':androidlibsvm-release')
}
apply plugin: 'com.google.gms.google-services'
I even downgraded my NDK version from 18 to 15 with no success.
Any ideas what might be the problem?
Help me, Obi-Wan Kenobi. You're my only hope.
EDIT:
This is my CMakeLists.txt, if it is of any help. I didn't change anything, should I?
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
Try to change your minSdkVersion and targetSdkVersion, i.e.
minSdkVersion 15
targetSdkVersion 23
I wish to include yctung's AndroidLibSVM into my project, so i followed his instructions to import the .AAR and set the dependencies.
Install
Install is easy, you just import our AAR library into your Android project >by the following steps:
Right-click your module -> new -> module -> Import .JAR/.AAR Package -> >select our Release/androidlibsvm-release.aar
After this, you should add the app dependency by:
Right-click your app module -> open module setting -> clieck your app -> >dependencies -> + -> module dependency -> androidlibsvm
Now I could import and work with his library as expected and Android Studio would compile the code and build without any errors. The app runs fine on an emulated device, however, it crashes on my physical device as soon as it tries to run the part of code referring to yctung's library with the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy" referenced by "/data/app/com.krautkremer.nils.mymirror-1/lib/arm/libjnilibsvm.so"
Referring to this SO-question, the error might be caused by incorrect Cmake/Gradle settings. If I get it right, Tung used ndk-build for his project, while I am building with Cmake. Therefor, his instructions on how to install his library may not be sufficient in my case. In fact, i haven't made any changes to the default CMakeLists.txt which i unterstand to be crucial for Cmake.
I tried to add a few lines in the build.gradle and/or the CmakeLists file as they are commonly suggested in SO-solutions with no success, but i have to admit, i really don't understand what i am doing, even after reading the official guide.
I am kind of lost here, since i hardly know the difference between ndk-build and Cmake, not to mention how to set them up correctly or if this is even necessary in this case.
I'd be most grateful if someone could explain to me, how i can integrate AndroidLibSVM into my project correctly, what changes i have to make to my gradle/cmake files and how i have to set up my directories (in case this is part of the answer).
All i've downloaded so far is the .aar which indeed does contain a few .so files but i don't understand where to put them.
Now,
this is my build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.krautkremer.nils.mymirror"
minSdkVersion 23
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
arguments "-DANDROID_PLATFORM=android-23"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
//exclude 'META-INF/proguard/androidx-annotations.pro'
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
implementation 'androidx.media:media:1.1.0-alpha01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
implementation 'com.google.android.material:material:1.1.0-alpha01'
implementation 'androidx.annotation:annotation:1.0.1'
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.google.firebase:firebase-ml-vision:18.0.2'
implementation 'com.google.firebase:firebase-ml-common:16.1.6'
implementation 'com.google.firebase:firebase-ml-vision-face-model:17.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1-alpha01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1-alpha01'
implementation project(':androidlibsvm-release')
}
apply plugin: 'com.google.gms.google-services'
and this is my CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp)
find_library(
log-lib
log)
target_link_libraries(
native-lib
${log-lib})
This is my directory structure.
Thank you in advance. If you need more to help me, i'd be happy to help you help me;)
I'm trying to make an android application that uses the Vulkan API for rendering, but I always get the "undefined reference to 'vkCreateInstance'" message.
Here is my CMakeList.txt:
cmake_minimum_required(VERSION 3.4.1)
add_library( native-lib
SHARED
src/main/cpp/native-lib.cpp)
add_library( vulkan_activity
SHARED
src/main/cpp/vulkan_activity.cpp)
add_library( vulkan_stuff
SHARED
src/main/cpp/vulkan_stuff.cpp)
add_library( vulkan_buffers
SHARED
src/main/cpp/vulkan_buffers.cpp)
find_library( log-lib
log )
target_link_libraries( native-lib
vulkan_stuffx
vulkan_activity
vulkan_buffers
vulkan
${log-lib})
And this is my build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.game.productions.phenyl.futuroland"
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions -v"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.google.android.gms:play-services-location:11.8.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
I want to build my application from scartch, so I don't want get anwsers like use the samples.
Android only has libvulkan.so on API 26 and higher (Nougat). Some devices supported it on Marshmallow, but you're not guaranteed that libvulkan.so will be present on API < 26, so the NDK won't let you link against it unless your NDK target platform is >= 26, since otherwise your app won't even launch on many of the devices that you say you want to be able to run on (minSdkVersion 16).
If you set minSdkVersion to 26, your native code should build against that version of the NDK headers/libraries, and libvulkan.so will be available at link time.
Or, if you're careful to only try to load your shared library that links against libvulkan.so when you're running on a Nougat device, you could leave minSdkVersion alone and add externalNativeBuild { cmake { arguments "-DANDROID_PLATFORM=android-26" } }. You'll want to carefully test on pre-Nougat devices or emulator images, since it's easy to accidentally end up with library dependencies that don't exist on earlier versions of the OS.
Or, instead of linking against libvulkan.so directly, you can use dlopen to load libvulkan.so at runtime, with a fallback or graceful exit if it fails, and then use dlsym() to get a pointer to vkGetInstanceProcAddr, and load everything else using that. This is the only way to use Vulkan on the Marshmallow devices that have it.