I am trying to use https://github.com/nlohmann/json in my Android app with C++. The issue is that when I go to build I get the error "no member named 'to_string' in namespace 'std'". I have followed the instructions on the Github for Android, except I have used Gradle to specify the stl and flags:
ndk {
stl "c++_static"
}
externalNativeBuild {
cmake {
cppFlags "-fexceptions -frtti -std=c++11"
}
}
Does anyone have any suggestions on how to make this library work on Android and use Gradle to set the stl properly?
Turns out I needed this instead (I have not looked into why though because the docs say what I posted should work):
externalNativeBuild {
cmake {
cppFlags "-fexceptions -frtti -std=c++11"
arguments "-DANDROID_STL=c++_shared"
}
}
Related
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"
}
}
Using Application.mk, it looks like the ABI targets can be selected with the option APP_ABI:
APP_ABI := armeabi-v7a,arm64-v8a,x86,x86_64,mips
I can't seem to find any such options for CMake builds. The file CMakeLists.txt seems to be called with the ANDROID_ABI option passed in, but I can't find any corresponding configuration options in the gradle plugin.
You should use abiFilters:
android {
defaultConfig {
ndk {
abiFilters "x86"
}
}
}
I am building my app in debug mode, and I notice some errors saying "parent failed to evaluate: no location, value may have been optimized out". Therefore, I try to add "-O0" in my module build.gradle like this:
externalNativeBuild {
cmake {
cppFlags "-O0 -frtti -fexceptions -std=c++11 -DANDROID_ARM_NEON=TRUE -mfloat-abi=softfp "
abiFilters "armeabi-v7a"
}
}
But still, the same error shows up after adding "-O0". May I ask how to disable compiler optimization properly? My android Studio version is 2.3.3, my sdk tool version is 26.0.2 and my ndk version is 15.1.4
If you want to disable optimization for release build, you can force Debug for C/C++ only:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments '-DCMAKE_BUILD_TYPE:STRING=Debug'
You can override the build flags by adding the following to your CMakeLists.txt:
# Debug flags
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
# Release flags
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast")
To verify this has worked check build output in:
app/.externalNativeBuild/cmake/<buildconfig>/<architecture>/build.ninja
Look for a line starting with FLAGS. This doesn't actually replace the existing compiler flags it just appends your flags and these take precedence.
The default flags are inherited from $ANDROID_NDK/build/cmake/android.toolchain.cmake so you could edit that file directly, however, if you update your NDK these changes will be overwritten.
Android Studio 2.2 Preview 1 has a new external ndk build feature, but from app/build.gradle snippet shown in official blog post it's not clear at all how to set additional ndk build parameters which Application.mk file usually contains
I'm able to set Android.mk ndk build file via externalNativeBuild, but how could I set the required Application.mk variables?
My Application.mk contains:
NDK_TOOLCHAIN_VERSION := clang
APP_PLATFORM := android-16
APP_ABI := armeabi
APP_STL := c++_static
APP_CPPFLAGS += -std=c++11
Android Studio 2.2 Preview 3 with updated gradle plugin added support for additional arguments. You can set Application.mk and additional configuration like this:
defaultConfig {
ndkBuild {
arguments "NDK_APPLICATION_MK:=Application.mk"
cFlags "-DTEST_C_FLAG1" "-DTEST_C_FLAG2"
cppFlags "-DTEST_CPP_FLAG2" "-DTEST_CPP_FLAG2"
abiFilters "armeabi-v7a", "armeabi"
}
}
If possible I would recommend migrating to CMake build system, because of better C++ code editor and debugging integration in Android Studio. You will find more info on gradle plugin configuration here:
https://sites.google.com/a/android.com/tools/tech-docs/external-c-builds.
Edit:
From Android Studio 2.2 Preview 5 you must wrap cmake and ndkBuild groups under externalNativeBuild group:
defaultConfig {
externalNativeBuild {
ndkBuild {
targets "target1", "target2"
arguments "NDK_APPLICATION_MK:=Application.mk"
cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2"
cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2"
abiFilters "armeabi-v7a", "armeabi"
}
}
}
Edit 2: It seems that wrapping ndkBuild under externalNativeBuild group does not work because of a bug in build tools.
add-native-code
android {
...
defaultConfig {...}
buildTypes {...}
// Encapsulates your external native build configurations.
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "CMakeLists.txt"
}
}
}
Note: If you want to link Gradle to an existing ndk-build project, use the ndkBuild {} block instead of cmake {}, and provide a relative path to your Android.mk file. Gradle also includes the Application.mk file if it is located in the same directory as your Android.mk file.
I try to compile my project with native c-libs and get next error
/Users/eugene/KREF14001/app/src/main/jni/libC/PulseFilter.c: In function 'shapeMonoGame':
/Users/eugene/KREF14001/app/src/main/jni/libC/PulseFilter.c:696:5: error: 'for' loop initial declarations are only allowed in C99 mode
/Users/eugene/KREF14001/app/src/main/jni/libC/PulseFilter.c:696:5: note: use option -std=c99 or -std=gnu99 to compile your code
From this report I find that I must to use option -std=c99 or -std=gnu99 to compile my code, but I don't know how to do it. Please, help me.
In the build.gradle file of your app, you can add cFlags "-std=c99" in the ndk block located within the defaultConfig block like this:
ndk {
moduleName "libblur"
abiFilter "armeabi-v7a"
stl "gnustl_static"
cFlags "-std=c99"
ldLibs "log"
}
The problem was in that the Gradle don't use your .mk files, but generate its own and use them. So it's useful to edit Android.mk and Application.mk. You can build your source code manually or edit ndk section of build.gradle.