Why does Prefab NDK Dependencies not work? - android

I have some native code that depends on OpenSSL. In the beginning, I tried manually compiling OpenSSL for Android, but it simply wouldn't find the definitions.
Then I decided to move on and try using Prefabs instead. I followed the example Android NDK Prefab example, but it just doesn't work.
My CMakeLists contains the following
find_package(openssl REQUIRED CONFIG)
target_link_libraries(
testproject
openssl::openssl)
My build.gradle:
android {
compileSdk 31
defaultConfig {
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures {
prefab true
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.android.ndk.thirdparty:openssl:1.1.1l-beta-1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
But whenever I compile, I get
Could not find a package configuration file provided by "openssl" with any
of the following names:
opensslConfig.cmake
openssl-config.cmake
Looking into the downloaded data, I see the openSSL folder under cmake only contains opensslConfigVersion.cmake and not opensslConfig.cmake, as it does with curl, for example.
What is going on? Why is this not working? Any help is appreiciated.

The curl-ssl example in the [ndk samples](gitclo https://github.com/android/ndk-samples)
only builds because it allows C++ and STL.
But openssl is C only.
The maven repo ndk thirdparty
links to the sources for the prefab package for openssl and curl among others,
i.e. ndkports.
There is no reference to C++ there for openssl.
It seems the problem is by prefab.
I found this issues: OpenSSL forces c++_shared – why?
Judging from this and other issues there is a high chance that prefab might just not fit your and my project as of yet.
You don't get an according curl message, because curl depends on openssl,
which makes the latter build first.
If you remove openssl you get:
Error: curl depends on unknown dependency openssl
I first did have no ndkVersion defined, as you.
Only afterward I got more error messages:
... //openssl/crypto. Rejected the following libraries:
C/C++: prefabandroid.arm64-v8a: User is targeting armeabi-v7a but library is for arm64-v8a
Removing armeabi-v7a from
ndk.abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
I got
... //openssl/ssl. Rejected the following libraries:
C/C++: prefabandroid.arm64-v8a: User requested no STL but library requires libc++
C/C++: prefabandroid.armeabi-v7a: User is targeting arm64-v8a but library is for armeabi-v7a
Another sign that prefab is ealily getting confused.
And because it was not built finally:
Could not find a package configuration file provided by "openssl" with any
of the following names:
··
opensslConfig.cmake
openssl-config.cmake
The file refers to
app/.cxx/cmake/debug/prefab/arm64-v8a/prefab/lib/aarch64-linux-android/cmake/openssl/opensslConfig.cmake
This has links that point to ~/.gradle.
So the include and link directories are somewhere deep down in ~/.gradle and not under the project directory.
One can include native code directly via cmake.
The ndkports are a starting point for to configuration.

Related

Debugger fails on documentation JNI C++ example (Windows and CMake)

Windows 7.
Android Studio Chipmunk 2021.2.1 Patch 2.
CMake.
Debugging "java only" apps works ok on the Nexus 5X.
Created the JNI C++ example (see https://developer.android.com/studio/projects/add-native-code#new-project).
CMakeLists.txt and gradle files all as generated.
App runs ok on Nexus 5X via USB.
Starting with debugger fails with the message:
Debugger process finished with exit code -1073741515 (0xC0000135). A library required by the native debugger might be missing on your system.
Which library "might be missing" and on which "system" Android Studio or Nexus 5X?
build.gradle (app):
plugins {
id 'com.android.application'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.example.testcpp2"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ''
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
}
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
CMakeLists.txt:
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("testcpp2")
# 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.
testcpp2
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
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.
testcpp2
# Links the target library to the log library
# included in the NDK.
${log-lib})
Thanks.

Android Tensorflow Lite C++ .SO libraries not linked on runtime

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.

App works fine on emulators, but crashes on device with: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy"

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

How do I parallelize externalNativeBuild for different ABIs?

Background
I'm currently working on an Android project which contains a fair amount of native code. The native code is built for multiple ABIs. For various reasons, the native code has up until now been built using a custom Gradle task that invokes ndk-build.cmd.
Now I'm in the process of changing this to use externalNativeBuild for the NDK integration, and CMake lists instead of the old Android.mk files. It seems like the better supported/documented way of doing things.
Problem
One nice thing about the old ndk-build method was that it would build for multiple ABIs in parallel - e.g. an ARM version and an x86 version of the library could be built in parallel.
This is especially helpful in my case, because I am required to use a 3rd party tool during the linking phase which 1) takes a very long time (minutes) to finish, and 2) is mostly single-threaded. Hence, building the library for multiple ABIs in parallel helped shorten my build times a lot.
When building with CMake / Ninja I cannot replicate this behavior. Ninja is supposed to parallelize builds by default, and it may well be doing that for a given ABI (i.e. compiling multiple source files in parallel for the same ABI). But from what I can tell, it never starts building the library for another ABI until it has finished building for the current ABI.
Question
When using CMake / Ninja through externalNativeBuild, is there any way I can tell the build system that I want it to build my native code for multiple ABIs in parallel?
Example
A minimal example to demonstrate this is as simple as the "New project" template in Android Studio, i.e. something like:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
add_library(native-lib SHARED
src/main/cpp/native-lib.cpp )
app/build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.example.cmakemultiabis"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters 'armeabi-v7a', 'x86'
}
}
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:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
And then building with e.g. gradlew assembleRelease will give you:
> Task :app:externalNativeBuildRelease
Build native-lib x86
[1/2] Building CXX object CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o
[2/2] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\release\obj\x86\libnative-lib.so
Build native-lib armeabi-v7a
[1/2] Building CXX object CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o
[2/2] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\release\obj\armeabi-v7a\libnative-lib.so
It may not be obvious from that output that the two libraries are built sequentially, but it does become obvious if you have something that takes a noticeable amount of time to link.
I have tried this both with the CMake / Ninja versions that you can download with the SDK Manager, as well as some newer versions (CMake 3.12.3, Ninja 1.8.2), and saw the same behavior in both cases.

Vulkan CMakeLists.txt?

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.

Categories

Resources