We have a project that uses a library that is built on top of Google's Mediapipe, which is built using the Bazel build system.
The project itself is an Android Native Library, built using Gradle with CMake
externalNativeBuild {
cmake {
cppFlags "-std=c++17 -fopenmp -static-openmp -fexceptions -frtti -Wl,-s -Wno-unused-command-line-argument"
arguments "-DANDROID_STL=c++_shared", "-DOpenCV_DIR=${opencvDir}", "-DANDROID_ARM_NEON=TRUE"
}
}
So we end up with 2 (or more later, also dependent on OpenCV for example) shared object libraries - the actual SDK & the Mediapipe project.
We're seeing issues that are similar to this, which lead me to look into the runtime part of our project.
E/libc++abi: terminating with uncaught exception of type std::bad_cast: std::bad_cast
I saw this comment on that issue thread, and adding
System.loadLibrary("c++_shared");
Solved the crash.
However, this is not a practical solution as the project we're building would provide a native SDK in the form of multiple .so files and I wouldn't want to force our clients to have to explicitly load the shared runtime library before using our library.
The gradle library has "-DANDROID_STL=c++_shared" flag, so this is using the shared one, but I couldn't find any way to compile Mediapipe (with Bazel) using c++_shared. I couldn't find any reference to using shared runtime when compiling Bazel projects (except for this, which isn't exactly relevant and the solution didn't help me)
We might be able to work around this by setting -DANDROID_STL=c++_static, but this has other issues, mainly, it violates Android's guidelines for using multiple shared libraries, though it might be possible for for middleware vendors
So the question is,
Is it possible to build Mediapipe (or any other Bazel based) using c++_shared Android STL
If not, are there any other options to solve the runtime conflicts
Is it even a runtime conflict or something else?
I managed to get it working as suggested by using c++_static on all of our shared objects (SDK, Mediapipe, OpenCV and others)
Related
I'm compiling a 3rd-party Java library for Android that uses JNI. I read the relevant pages on adding C++ support on developer.android but I'm still confused about a couple of issues regarding C++ STL runtime that I was hoping I could clear up here:
1- My library has no control over the app it will be embedded in, so I don't know if there will be other libraries that might use a static/shared STLs. If I use a static C++ runtime with ANDROID_STL=c++_static, is it safe, or should I have to worry about another library that could be using something like gnustl_static which might conflict with mine?
2- If I use a shared C++ runtime with ANDROID_STL=c++_shared, is it a guarantee that a specific element in the STL will use the libc++ runtime or could it be possible to use gnustl if it doesn't exist? For example, If I was using std::string with a shared c++ runtime (c++_shared) in an app that has another library of gnustl_static, will my std::string implementation be taken from libc++ or gnustl?
Ideally, I'd like to have a very stripped down version of a static c++ runtime with (c++_static) that only includes std::vector, std::string and std::map. I was actually planning to use something like -ffunction-sections as described here and #768.
Please advise and thank you.
Environment Details
Pkg.Desc = Android NDK
Pkg.Revision = r15c
Android Studio = 3.1.2
system: cmake Host OS: Arch Linux ($ uname -r % 4.18.5-arch1-1-ARCH)
Compiler: Clang++
STL: c++_static/c++_shared
Your concern is a very real one. But if handled properly, you can find a robust way out.
The warnings about using single C++ runtime across all libraries in the app (and the whole idea to define C++ support in NDK as APP_STL vs. most other flags such as LOCAL_CFLAGS or LOCAL_SHARED_LIBRARIES, are relevant for the native libraries that are connected. JNI libraries that never communicate directly (except through their corresponding Java layers) can use different C++ runtimes. Another point is that normal build will only package one C++ runtime shared lib into the APK. Note that versioning is also a potential hazard: if a developer who adds your library uses a different NDK release, there might be collisions or unexpected side effects when his version of STL runtime works with your code.
Therefore, to achieve maximum flexibility, your library should use a static C++ runtime. This may effect the size of the binary, but if, as you say, you use only a limited subset of STL, this extra will be rather small.
The bottom line, you will have minimum to worry about if build your shared library with libc++_static.
I have an android project that currently uses Cmake for including all .cpp /.c code. Now I want to add the GStreamer native libraries such that I can use them in my native code.
But the gstreamer docs https://gstreamer.freedesktop.org/documentation/installing/for-android-development.html
only document using ndk-build to use gstreamer on android.
Now I don't want to totally refactor my project to use ndk-build and Android.mk because
CMake does its job and i never had problems with it
as stated here cmake is the default for android ndk https://developer.android.com/studio/projects/add-native-code
I also need to include the googlevr ndk library that uses cmake.
So I need to figure out a workaround and therefore need your help. Here are some ideas I came up with
Each module can have ether cmake or ndk-build support. Therefore,
I probably could add a new module using ndk-build and include gstreamer there (but then gstreamer is only available in this module)
Compile gstreamer for android using cmake inside android studio - but I don't see evidence that has been done before or is possible for someone without strong cmake knowledge.
Any other ideas/ improvements ? thanks
Even though you have already moved away from GStreamer but in case someone else is facing this issue please have a look at following github repository
https://github.com/henkeldi/gstreamer-android
For myself, I had to make two modifications
I modified the definition of GSTREAMER_ROOT to include ANDROID_ABI so it looks like following
#GStreamer
set(GSTREAMER_ROOT $ENV{GSTREAMER_ROOT_ANDROID}/${ANDROID_ABI})
I had to rename the folders in GStreamer pre-built binaries to be according to ANDROID_ABI. So, my Gstreamer pre-built binaries folder look like following
After the above changes, I am able to successfully build with APK with GStreamer using CMake
At some point I gave up on gstreamer and am now using ffmpeg instead.
There is a nice tutorial for compiling ffmpeg that makes including native ffmpeg inside an android project really easy:
Tutorial on Medium
Github project
I am compiling C++ library code in Android Studio 2.2. I follow the new guide, where I add all the files to my project and compile it using CMake (and CMakeLists.txt) like this. I want to use C++14 features, and stuff like atomic, stoi etc. but the building is failing with errors.
error: no type named 'condition_variable' in namespace 'std'
error: no member named 'stoi' in namespace 'std'
This is what my CMakeLists looks like (other lines set source files and other stuff):
find_library(GLES GLESv2)
include_directories(${COMMON_PATH} /usr/local/include)
set(ANDROID_STL "c++_shared")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -latomic")
add_library(native-lib SHARED ${COMMON_SRC})
target_link_libraries(native-lib ${GLES})
I found this article on the android page (here), but I don't know how and if I can do this when using CMakeLists and not ndk-build. I see other question that solve it using the c++_static runtime but only with ndk-build.
This documentation would be more useful for cmake case:
arguments "-DANDROID_STL=c++_shared
Gradle also packs libc++_shared.so into APK when using c++_shared; bypassing Gradle might cause trouble for your app on early version of Android OS.
at the time of this question, Android Studio might have trouble; at the time now Android Studio 3.1.3, it should be ok
The cross-compilation process used to generate the native libraries for Android uses the c++ dependencies from the NDK libraries. The NDK provided by Google is good and it has lots of things, but the C++11 and C++14 support is not complete.
If you want to use C++14 features, you can use other NDK like CrystaX NDK for example. With CrystaX you have also C++17 support.
I am developing a library for Android which has both Java and Native components. The Native library depends on the GNU STL. I was linking against gnustl_static, but have ran into a few strange problems that were resolved by linking gnustl_shared. (for example the question Filesystem and locale). For the time being, I have settled on gnustl_shared.
Here's where the question is -- the consumer of my library is expected to link against the Native .so to add code of their own. I understand from reading that all the C-runtimes must match.
Demanding my clients use gnustl_shared seems like it might not work (as far as diplomacy and ease of integration goes)
If I build with gnustl_shared, the JAR file generated contains libgnustl_shared.so, which causes a problem building an APK which also relies on this library. -- I suppose I can just not include it in the JAR file?
If I build against gnustl_static do I avoid all these problems?
If my API contains refernces to STL objects (mostly std::string and std::vector), will I face problems if my clients do not use GNU STL?
thanks
I'm using the newest Android NDK r6b to build my shared object. This library does not use any kind of STL at all, but resulting .so includes many STL stuff like std::bad_alloc_what(void) and many more, which increases size of binary greatly. Also release builds include this garbage. APP_STL not defined anywhere, also the NDK r5b produces small binary with used functions only. Is it a bug of r6b? How can I build with r6b without STL stuff?
It seems that there is a bug in NDK r6b and it always builds libraries with exceptions support, even if -fno-exceptions is explicitly specified.
See this question for details: Android NDK produce unreasonable big binaries, how to optimize .so size?
If you are using, say, new then you are implicitly using the standard library for the std::bad_alloc exception. Unless you call the no-throw version of new, which would instead use std::nothrow. If you don't use the standard library, then it won't get linked. Just make sure you don't, if that's what you want, or perhaps just move to C?