我必须在一个Android项目中使用opencv。一切正常,直到最近我也不得不使用c ++ exception_ptr为止。
从那时起,使用std::rethrow_exception
会导致SIGBUS(信号SIGBUS:非法对齐)。
我创建了一个最小的示例来说明问题。该示例应用程序仅链接到opencv 3.4.4,但未使用任何opencv函数。如果您在CMakeLists.txt
中删除了与opencv的链接,则该应用程序将正常运行并且不会崩溃。但是,如果添加它,则应用程序将在调用本机方法triggerException()
时崩溃。
在我的实现中,如果按下按钮,示例应用程序将调用此方法。
native-lib.cpp:
#include <jni.h>
#include <string>
#include <exception>
/*
* code based on: https://en.cppreference.com/w/cpp/error/exception_ptr
*/
std::string handle_eptr2(std::exception_ptr eptr)
{
try {
if (eptr) {
std::rethrow_exception(eptr);
}
} catch (const std::exception &e) {
return "Caught exception \"" + std::string(e.what()) + "\"\n";
}
return "Something went wrong";
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_user_exceptiontest_MainActivity_triggerException(
JNIEnv *env,
jobject /* this */) {
std::exception_ptr eptr;
try {
std::string().at(1); // this generates an std::out_of_range
} catch(...) {
eptr = std::current_exception(); // capture
}
std::string res = handle_eptr2(eptr);
return env->NewStringUTF(res.c_str());
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
set(OPENCV_DIR $ENV{HOME}/lib/OpenCV-android-sdk/sdk )
include_directories(${OPENCV_DIR}/native/jni/include )
add_library( native-lib
SHARED
src/main/cpp/native-lib.cpp)
find_library( log-lib
log)
target_link_libraries(
native-lib
# Removing the following line will make everything work as expected (what() message is returned)
${OPENCV_DIR}/native/libs/${ANDROID_ABI}/libopencv_java3.so # <--- critical line
${log-lib})
build.gradle
要使用异常和c ++ 17支持,我在android-studio创建的配置中添加了以下几行。
externalNativeBuild {
cmake {
arguments '-DANDROID_TOOLCHAIN=clang',
'-DANDROID_STL=c++_shared'
cppFlags "-std=c++1z -frtti -fexceptions"
}
}
堆栈跟踪:
<unknown> 0x004c4e47432b2b01
___lldb_unnamed_symbol15856$$libopencv_java3.so 0x0000007f811c4a58
_Unwind_Resume_or_Rethrow 0x0000007f811c4fc8
__cxa_rethrow 0x0000007f81181e50
__gnu_cxx::__verbose_terminate_handler() 0x0000007f811b1580
__cxxabiv1::__terminate(void (*)()) 0x0000007f81181c54
std::terminate() 0x0000007f81181cc0
std::rethrow_exception(std::exception_ptr) 0x0000007f802db2cc
handle_eptr2(std::exception_ptr) native-lib.cpp:35
::Java_com_example_user_exceptiontest_MainActivity_triggerException(JNIEnv *, jobject) native-lib.cpp:58
在寻找解决方案时,我查看了opencv源代码(https://github.com/opencv/opencv/blob/master/modules/core/src/parallel.cpp),偶然发现了以下代码片段:
#ifndef CV__EXCEPTION_PTR
# if defined(__ANDROID__) && defined(ATOMIC_INT_LOCK_FREE) && ATOMIC_INT_LOCK_FREE < 2
# define CV__EXCEPTION_PTR 0 // Not supported, details: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58938
我知道这是否会改变opencv的行为,但是我不知道这可能会如何影响根本不使用opencv的代码。
编辑:值得一提的是,如果我在Linux(x86_64)桌面设置(clang,libc ++,opencv3.4.4)中直接(不使用jni)使用此代码,则链接到opencv不会产生任何影响。因此,我的结论是这是android特有的问题...
有人知道如何解决该问题或下一步尝试什么吗? 提前非常感谢!
答案 0 :(得分:1)
在使用c ++ stl时,Opencv是使用gnu运行时进行编译的。参见One STL per app。您将需要使用gnustl(为此需要回到ndk 15)或使用c ++ stl构建opencv。
为了使用c ++ _ static构建opencv,您可以尝试遵循comment in opencv bugtracker
cmake -GNinja -DINSTALL_ANDROID_EXAMPLES = ON -DANDROID_EXAMPLES_WITH_LIBS = ON -DBUILD_EXAMPLES = ON -DBUILD_DOCS = OFF -DWITH_OPENCL = OFF -DWITH_IPP = ON -DCMAKE_TOOLCHAIN_FILE = $ {ANDROID_NDK} /build/cmake/android.toolchain.cmake -DANDROID_TOOLCHAIN = c语“ -DANDROID_STL = c ++ _ static” -DANDROID_ABI = x86 -DANDROID_SDK_TARGET = 18 ../ opencv
之后
进行&&进行安装