How to set NDK lib path in Gradle? - android

I'm working on a PDF viewer application using ebookdroid & MuPDF CPP files. I am having lots of problem with NDK integration in Gradle. I've gone through many answers but they have not fixed my problem.
Gradle is giving me the following error message:
Error:Execution failed for task ':app:compileDebugNdk'.
Error: Your project contains C++ files but it is not using a supported native build system.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.

Edit your build.gradle, add defaultConfig.externalNativeBuild.ndkBuild, externalNativeBuild.ndkBuild and sourceSet.main.jni.srcDir options. See the comments below.
android {
compileSdkVersion 22
buildToolsVersion "27.0.0"
defaultConfig {
minSdkVersion 18
targetSdkVersion 22
versionCode 1
versionName "1.0"
//add arguments passed to ndkBuild
externalNativeBuild {
ndkBuild {
arguments "NDK_TOOLCHAIN_VERSION=clang", "APP_SHORT_COMMANDS=true", "APP_ALLOW_MISSING_DEPS=true"
arguments "-j" + Runtime.runtime.availableProcessors()
cFlags "-fexceptions"
}
}
ndk {
abiFilters "armeabi-v7a"
}
}
//specify jni source file path
sourceSets.main {
java.srcDir "src"
res.srcDir "res"
jni.srcDir "jni"
}
buildTypes {
debug {
debuggable true
jniDebuggable true
}
}
//specify makefile / CMake file
externalNativeBuild {
ndkBuild {
path 'jni/Android.mk'
}
}
}

Related

Why Android Studio 3 use cmake 3.6.0 as default?

My Android studio is version 3.3.2 and i trying to link gradle to my native library, my module's build.gradle is:
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 18
targetSdkVersion 28
versionCode 1
versionName "1.0"
ndk {
moduleName "MyModule"
abiFilters 'x86', 'armeabi-v7a'
}
}
externalNativeBuild {
cmake {
version "3.10.2" // The key line
path file('CMakeLists.txt')
}
}
}
If i don't specify the cmake version to '3.10.2', I am getting the following error:
CMake '3.6.0' was not found in PATH or by cmake.dir property.
- CMake '3.10.2' found in SDK did not match requested version '3.6.0'.
- CMake '3.12.1' found in PATH did not match requested version '3.6.0'.
Install CMake 3.6.0
So I'am confused why is so! Why does it ask for the version of cmake itself to be 3.6.0.
Kindly review and give feedback.
Try to add the configuration below to your gradle:
externalNativeBuild {
cmake {
version "3.10.2" // here
}
}

CMAKE not obeying flags from gradle for NDK building on Android

I have an Android NDK project which I am trying to build through Gradle+CMake.
build.gradle:
apply plugin: 'com.android.library'
allprojects {
repositories {
jcenter()
google()
}
}
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_ABI=armeabi-v7a",
"-DANDROID_PLATFORM=android-16",
"-DANDROID_STL=gnustl_static",
"-DANDROID_CPP_FEATURES=rtti exceptions",
"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=libs"
}
}
}
buildTypes {
release {
ndk {
abiFilters "armeabi-v7a"
}
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
ndk {
abiFilters "armeabi-v7a"
}
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
CMAKE Command Output:
Executable : /Users/ssk/Library/Android/sdk/cmake/3.6.3155560/bin/cmake
arguments :
-H/Users/ssk/MyProject
-B/Users/ssk/MyProject/.externalNativeBuild/cmake/debug/armeabi-v7a
-DANDROID_ABI=armeabi-v7a
-DANDROID_PLATFORM=android-16
------> -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/Users/ssk/MyProject/build/intermediates/cmake/debug/obj/armeabi-v7a
-DCMAKE_BUILD_TYPE=Debug
-DANDROID_NDK=/Users/ssk/Library/Android/sdk/ndk-bundle
-DCMAKE_CXX_FLAGS=-std=c++11
-DCMAKE_TOOLCHAIN_FILE=/Users/ssk/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake
-DCMAKE_MAKE_PROGRAM=/Users/ssk/Library/Android/sdk/cmake/3.6.3155560/bin/ninja
-GAndroid Gradle - Ninja
-DANDROID_STL=gnustl_static
-DANDROID_ABI=armeabi-v7a
-DANDROID_PLATFORM=android-16
-DANDROID_CPP_FEATURES=rtti exceptions
------> -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=libs
jvmArgs :
I am trying to configure the output directory using DCMAKE_LIBRARY_OUTPUT_DIRECTORY, but it's not obeying.
Gradle prefixes a default one before my option as highlighted (------> in cmake command output).
Question:
How should I configure the output directory?
Below snippet will configure your output directory:
For static lib output directory, try below:
# copy out the static lib binary
set_target_properties(${STATIC_LIBRARY_NAME}
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "libs/${ANDROID_ABI}")
For shared lib output directory, try below:
# copy out the shared lib binary
set_target_properties(${SHARED_LIBRARY_NAME}
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "libs/${ANDROID_ABI}")
Explanation:
ANDROID_ABI is a variable defining the Android ABI, e.g. armeabi-v7a
Reference about the CMake variables definition:
Android NDK path variable for "strip" command in CMake build tool chain
Probably you need to set the buildStagingDirectory option. In the next link you will find how to manage paths for CMake in gradle:
CMakeOptions
And as a side note unrelated to the question. In your gradle script seems you are still using gnustl_static which is no longer supported and will be removed in the next NDK versions. You should switch to either c++_static or c++_shared. Take into account that gcc has been deprecated and you should use clang. Next an example:
externalNativeBuild {
cmake {
arguments "-DANDROID_PLATFORM=android-16", "-DANDROID_STL=c++_static", "-DANDROID_TOOLCHAIN=clang"
abiFilters "armeabi-v7a", "arm64-v8a", "x86"
}
}

Could not find method cppFlags() arguments() for arguments

I am trying to use
std::function
But the compiler throws an error
Error:(50, 10) error: no type named 'function' in namespace 'std'
I have tried to modify the build.gradle file
externalNativeBuild {
ndkBuild {
path "src/main/jni/Android.mk"
}
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_STL=gnustl_static"
path 'src/main/jni/CMakeLists.txt'
}
}
But it doesn't accept arguments other than path and throws the following errors
Error:(28, 0) Could not find method arguments() for arguments [-DANDROID_STL=gnustl_static] on object of type com.android.build.gradle.internal.dsl.CmakeOptions.
Please help me to be able to use
std::function
UPDATE
Thanks to #Alex Cohn I was able to configure flags and arguments, and now my file looks like that
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_STL=gnustl_static"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
/* ndkBuild {
path "src/main/jni/Android.mk"
}*/
cmake {
// cppFlags "-std=c++11"
//arguments "-DANDROID_STL=gnustl_static"
path 'src/main/jni/CMakeLists.txt'
}
}
}
dependencies {
compile 'com.android.support:support-annotations:25.0.1'
}
There are two entirely different blocks in build.gradle that are named externalNativeBuild (thanks, Google).
One is under android top-level block, and it specifies the path to native build script, cmake or ndkBuild (but not both).
The other can be used to specify, from gradle, some parameters for the native build. This block is usually a child of the defaultConfig block, but can also appear for flavors (see an example).
These externalNativeBuild blocks can also have cmake or ndkBuild children, but only the child that matches the path setting (see above) is relevant, the other is silently ignored.
The bottom line, split your block in two, and put each one in correct place in build.gradle hierarchy.

Android Studio copy external native build libraries from multiple ABIs to jniLibs

I am building external native build library with multiple ABIs armeabi-v7a and x86 with Android Studio. The problem is that when I build the project the libraries are in these folders:
App/.externalNativeBuild/cmake/debug/armeabi-v7a/libs/armeabi-v7a/libApp.so
App/.externalNativeBuild/cmake/debug/x86/libs/x86/libApp.so
Where they should be in inside these locations in order to be found correctly on the device:
App/src/main/jniLibs/armeabi-v7a/libApp.so
App/src/main/jniLibs/x86/libApp.so
Is there a way that they can be generated or build directly into jniLibs? At the moment I have done symlinks by hand but I hope there is automated way of handling different ABIs and different configurations.
This is my current gradle script:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.org.app"
minSdkVersion 19
targetSdkVersion 19
ndk {
abiFilters 'armeabi-v7a', 'x86'
stl = "c++_static"
}
externalNativeBuild {
cmake {
arguments "-DCMAKE_BUILD_TYPE=Release"
}
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')
}
}
externalNativeBuild {
cmake {
path '../../../CMakeLists.txt'
}
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir 'src/main/jniLibs'
}
}
Use
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDirs 'src/main/jniLibs'
}

How to setup Android library module with productflavors and jni

I'm trying to include mupdf as an android library module with precompiled .so binaries into my project.
I have an application module which includes my library module like so.
dependencies {
compile project(':mupdf')
}
In my mupdf library module I have my compiled binaries like so.
mupdf
- jniLibs
- arm64-v8a
libmupdf.so
- armeabi
libmupdf.so
- armeabi-v7a
libmupdf.so
- x86
libmupdf.so
- x86_64
libmupdf.so
My build.gradle for the mupdf library project:
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
publishNonDefault true
productFlavors {
x86 {
ndk {
abiFilter "x86"
}
}
x64 {
ndk {
abiFilter "x86_64"
}
}
arm {
ndk {
abiFilter "armeabi"
}
}
arm_v7a {
ndk {
abiFilter "armeabi-v7a"
}
}
arm64_v8a {
ndk {
abiFilter "arm64-v8a"
}
}
fat
}
}
dependencies{
compile project(':core')
}
The problem is soon as I add the product flavors my app doesn't compile because it doesn't find any of the java files from the mupdf module.
If I delete the product flavors part from the gradle file it compiles. But it crashes at runtime because it can't resolve/load the libmupdf library.
You can do this without product flavors. Just remove them and call System.loadLibrary("mupdf") on startup/at some point before the library is used. This call will figure out which native lib to use for the current devices architecture.
Indeed I have to build a fat module for the .aar library and apply the productflavors in my app.gradle.
I was missing this in my library's build.gradle
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir 'src/main/jni'
}
Without this no methods were able to be resolved.

Categories

Resources