Android : gradle building libraries for all ABIs - android

I am working on an android native project which uses C++ code. I am using CMake to build C++ libraries. I am specifying CMake arguments like this in build.gradle:
cmake {
arguments "--warn-uninitialized",
"-DANDROID_TOOLCHAIN=clang",
"-DANDROID_STL=c++_shared",
"-DANDROID_PLATFORM=android-21",
"-DAPP_ALLOW_MISSING_DEPS=true",
"-DSHARED_LIBRARY=1",
"-DOFFLINE_SYNC_SUPPORT_ENABLED=0",
"-DT5_TARGET_PLATFORM=Android",
"-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a",
"-DANDROID_ABI=armeabi-v7a"
What I want gradle is to build libraries only for armeabi-v7a as specified in cmake arguments but gradle by default is building code for all ABIs.
Though abiFilters can be used in gradle but my gradle build is being invoked by command-line where user has to specify ABI in command line and libs only for that ABI should be built. Like ./gradlew v7 should only build armeabi-v7a libs.

Related

Build OpenCV for Android with CMake's ExternalProject_Add

I am creating an Android library that uses OpenCV via NDK. It doesn't require any Java parts of OpenCV, native parts only, so I decided not to use OpenCV for Android to reduce the size of the OpenCV code the library needs.
Now I need to download and build the native (C++) part of OpenCV using CMake so that the library won't require its users to download and install OpenCV on their own.
Currently my module's build.gradle contains this:
externalNativeBuild {
cmake {
cppFlags '-std=c++11 -frtti -fexceptions'
arguments '-DANDROID_ARM_NEON=TRUE'
}
}
And my CMakeLists.txt is:
cmake_minimum_required(VERSION 3.18.1)
project("mylib")
set(OPENCV_INSTALL_DIR ${CMAKE_BINARY_DIR}/opencv-install)
include(ExternalProject)
ExternalProject_Add(opencv
GIT_REPOSITORY https://github.com/opencv/opencv.git
GIT_TAG 4.5.5
UPDATE_DISCONNECTED TRUE
CMAKE_ARGS
<OpenCV arguments I need>
-DCMAKE_INSTALL_PREFIX=${OPENCV_INSTALL_DIR}
)
include_directories(${OPENCV_INSTALL_DIR}/include)
link_directories(${OPENCV_INSTALL_DIR}/lib)
set(OPENCV_LIBRARIES <OpenCV modules I use>)
add_library(mylib SHARED mylib.cpp)
add_dependencies(mylib opencv)
find_library(log-lib log)
target_link_libraries(mylib ${log-lib} ${OPENCV_LIBRARIES})
I am using Android Studio. When I try to build the library, the downloading process goes fine, but at the configure step I get the following error:
FAILED: opencv-prefix/src/opencv-stamp/opencv-configure
cmd.exe /C "cd /D <my lib module path>\.cxx\Debug\612145b5\x86_64\opencv-prefix\src\opencv-build && <my Android SDK path>\cmake\3.18.1\bin\cmake.exe -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_opencv_apps=OFF -DBUILD_JAVA=OFF -DBUILD_FAT_JAVA_LIB=OFF -DBUILD_opencv_python2=OFF -DBUILD_opencv_python3=OFF -DWITH_GTK=OFF -DWITH_WIN32UI=OFF -DWITH_FFMPEG=OFF -DWITH_V4L=OFF -DCPU_BASELINE=NEON -DCMAKE_INSTALL_PREFIX=<my lib module path>/.cxx/Debug/612145b5/x86_64/opencv-install -GNinja <my lib module path>/.cxx/Debug/612145b5/x86_64/opencv-prefix/src/opencv && <my Android SDK path>\cmake\3.18.1\bin\cmake.exe -E touch <my lib module path>/.cxx/Debug/612145b5/x86_64/opencv-prefix/src/opencv-stamp/opencv-configure"
CMake Error: CMake was unable to find a build program corresponding to "Ninja". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
As I see, CMake cannot find the following components:
Ninja
C++ compiler
C compiler
I can get rid of the first error, if I add ninja's path from NDK to the PATH variable, I don't think thats how it should be done though. Neither do I want to pass CMAKE_CXX_COMPILER and CMAKE_C_COMPILER to CMake manually, as it seems like it should be done automatically by Android Studio.
So, how can I fix this?

How to build an Android project with Ninja?

I have an Android project with a app/src/CMakeLists.txt file like this
cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
main/cpp/native-lib.cpp )
I also have a app/src/main/cpp/native-lib.cpp file in my project.
When I run ninja in a terminal I get this error
ninja: error: loading 'build.ninja': No such file or directory
I'm not familiar with the NDK and I'm trying to run the project with ninja but I'm not able to find any clear documentation or example.
Android NDK uses CMake to build projects, but instead of run ninja separately, you should run below gradle command to trigger your NDK project build.
./gradlew externalNativeBuild
Internally, CMake will use the ninja build system to compile and link the C/C++ sources for your apps.

Android Studio CMake/Ninja Not Used for Building an NDK project

I have the following CMAKE & Ninja installed through Android Studio's SDK Tools:
~/Library/Android/sdk/cmake/3.10.2.4988404/bin/ninja --version
1.8.2
I run into "Error Configuring" while trying to build my project. Here is the build output:
Executable : /Users/ssk/Library/Android/sdk/cmake/3.10.2.4988404/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_SYSTEM_NAME=Android
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_SYSTEM_VERSION=16
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_ANDROID_NDK=/Users/ssk/Library/Android/sdk/ndk-bundle
-DCMAKE_TOOLCHAIN_FILE=/Users/ssk/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake
-G Ninja
-DANDROID_STL=gnustl_statics
-DANDROID_CPP_FEATURES=rtti exception
-DANDROID_TOOLCHAIN=gcc
-DANDROID_NDK=/Users/ssk/android-ndk-r17c/
jvmArgs :
It's missing:
-DCMAKE_MAKE_PROGRAM=/Users/ssk/Library/Android/sdk/cmake/3.10.2.4988404/bin/ninja
Error:
CMake was unable to find a build program corresponding to "Ninja". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool
Only if I switch to CMake version say 3.6.3155560 it works. Otherwise, I have to install ninja from brew or macports.
Here is the snippet from my build.gradle:
externalNativeBuild {
cmake {
// Linker flags and Visibility options keeps the size of the library small
cppFlags "-std=c++11"
arguments "-DANDROID_STL=gnustl_static",
"-DANDROID_CPP_FEATURES=rtti exceptions",
"-DANDROID_TOOLCHAIN=gcc"
}
}
How to fix it?
Install/Update CMake From Android Studio SDK Manager
Check your CMake from sdk root directory if ninja exists.
Below is not good.
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"
}
Because, ANDROID_PLATFORM should be automatically decided by Android external native build system according to minSdkVersion, see below official document from how ANDROID_PLATFORM works:
Instead of changing this flag directly, you should set the minSdkVersion property in the defaultConfig or productFlavors blocks of your module-level build.gradle file. This makes sure your library is used only by apps installed on devices running an adequate version of Android. The CMake toolchain then chooses the best platform version for the ABI you're building using the following logic:
If there exists a platform version for the ABI equal to minSdkVersion, CMake uses that version.
Otherwise,
if there exists platform versions lower than minSdkVersion for the ABI, CMake uses the highest of those platform versions. This is a reasonable choice because a missing platform version typically means that there were no changes to the native platform APIs since the previous available version.
Otherwise, CMake uses the next available platform version higher than minSdkVersion.
And, -DANDROID_ABI=armeabi-v7a is not good as well. You should not define this parameter here. CMake will iterate all your ABIs according to your abiFilters automatically. If you just want to build armeabi-v7a, you can specify this using abiFilter, e.g.
externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
Also, rtti and exceptions are cppFlags, below should be the proper way to set these two flags.
cppFlags "-std=c++11 -frtti -fexceptions"
Ensure that your have properly configured ANDROID_NDK path, because according to your question, you have TWO version of NDK set, one is -DANDROID_NDK=/Users/ssk/android-ndk-r17c/, the other one is -DANDROID_NDK=/Users/ssk/Library/Android/sdk/ndk-bundle. Config NDK path from local.properties:
ndk.dir=/Users/ssk/Library/Android/sdk/ndk-bundle
sdk.dir=/Users/ssk/Library/Android/sdk
what is the fix for -GAndroid Gradle - Ninja?
Add below arguments to the cmake config:
externalNativeBuild {
cmake {
...
version "3.10.2"
arguments "-GAndroid Gradle - Ninja"
}
}

Canot build Android NDK project after latest NDK update and gcc deprecation

I have updated Android NDK to latest version available and now my project doesn't compile anymore.
At the first attempt to compile the project I received a message about gcc deprecation and invite to replace It with clang.
So I have tried to edit
externalNativeBuild {
cmake {
arguments '-DANDROID_TOOLCHAIN=gcc', '-DANDROID_STL=gnustl_static'
}
}
In
externalNativeBuild {
cmake {
arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_static'
}
}
But unfortunately now I get the error:
Error while executing process C:\Android\android-sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {-HD:\My Project\myApp\jni -BD:\My Project\myApp\.externalNativeBuild\cmake\release\armeabi-v7a -DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=android-21 -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=D:\My Project\myApp\gradleBuild\intermediates\cmake\release\obj\armeabi-v7a -DCMAKE_BUILD_TYPE=Release -DANDROID_NDK=C:\Android\android-sdk\ndk-bundle -DCMAKE_TOOLCHAIN_FILE=C:\Android\android-sdk\ndk-bundle\build\cmake\android.toolchain.cmake -DCMAKE_MAKE_PROGRAM=C:\Android\android-sdk\cmake\3.6.4111459\bin\ninja.exe -GAndroid Gradle - Ninja -DANDROID_TOOLCHAIN=clang -DANDROID_STL=gnustl_static}
The project compilation before the NDK update worked fine.
Don't try to build NDK when the path to your sources contains spaces.
The latest NDK deprecated gnustl, too. Try c++_shared instead.
You don't need to specify ANDROID_TOOLCHAIN in arguments.
Make sure you use a version of gradle Android plugin that is compatible with the latest NDK, see https://developer.android.com/studio/releases/gradle-plugin.
This runtime is tightly coupled to GCC, which is no longer supported in the NDK. As such, it has not received updates for several releases. The version in the NDK supports most of C++11 (see Issue 82), and some portions of this library are incompatible with Clang.
gnustl
This library is deprecated and will be removed in NDK r18. Beginning with NDK r16, you should use libc++ instead.
You should use "-DANDROID_STL=c++_static" instead of -DANDROID_STL=gnustl_static

gradle + ndkbuild + android studio 2.2 how to set supported ABIs?

I want to use android studio integration with ndkbuild.
My "native" part of project build only for armeabi-v7a-hard and x86,
and all works fine if I just run ndk-build in jni directory.
I have proper lines in Application.mk:
APP_ABI := armeabi-v7a-hard x86
To integration project into android studio I added such lines into build.gradle:
externalNativeBuild {
ndkBuild {
path 'src/lib/jni/Android.mk'
}
}
But for some reason gradle build try build native code with APP_ABI=armeabi and failed, because of my code can only be build with armeabi-v7a-hard.
So how can I tell gradle to build my code only for armeabi-v7a-hard and x86,
or just not ignore APP_ABI line from Application.mk?
I try such variant:
defaultConfig {
ndk {
abiFilters 'x86', 'armeabi-v7a-hard'
}
}
but gradle failed with such message:
ABIs [armeabi-v7a-hard] are not available for platform and will be
excluded from building and packaging. Available ABIs are [armeabi,
armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64].
Note, that I use ndk 10, not last one (ndk 13), where there is armeabi-v7a-hard, and ndk.dir in local.properties to right value.
Link provided by #Titan is all you need to set the ABI.
The reason why it might not be working is because armeabi-v7a-hard is deprecated in 2015, so targeting it is resulting in this issue. You should target armeabi-v7a as per this this post

Categories

Resources