error: undefined reference to 'cv::Mat::~Mat()' Solve the problem of compilation error when AndroidStudio integrates OpenVC

foreword

Originally, this type of blog was not what the author wanted to write, but the author searched the Internet for this problem but there was no available solution, so I shared it to help everyone fill in the hole.

Integrate OpenVC static library

The official Android SDK of OpenCV is downloaded here , and the integration method will not be introduced much. You can read the articles of these two bloggers:

The complete configuration file of CMakeList.txt is as follows:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.18.1)

# Declares and names the project.

project("opencv_mobile")

include_directories(include)

# 设置Debug编译模式,这样才能生成符号表,方便使用addr2line来定位内存地址对应代码行
set(CMAKE_BUILD_TYPE DEBUG)

# 设置变量
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti -fexceptions -fopenmp -static-openmp")
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv/sdk/native/jni)
find_package(OpenCV 4.5.4 REQUIRED core features2d highgui imgproc photo video)
message("OpenCV_FOUND is ${OpenCV_FOUND}")
message("OpenCV_LIBS is ${OpenCV_LIBS}")

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        opencv_mobile

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        opencv_mobile.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
        opencv_mobile
        ${OpenCV_LIBS}
        # Links the target library to the log library
        # included in the NDK.
        android
        ${log-lib})

The official OpenCVConfig.cmake also tells us how to integrate.

# ===================================================================================
#  The OpenCV CMake configuration file
#
#             ** File generated automatically, do not modify **
#
#  Usage from an external project:
#    In your CMakeLists.txt, add these lines:
#
#    find_package(OpenCV REQUIRED)
#    include_directories(${OpenCV_INCLUDE_DIRS}) # Not needed for CMake >= 2.8.11
#    target_link_libraries(MY_TARGET_NAME ${OpenCV_LIBS})
#
#    Or you can search for specific OpenCV modules:
#
#    find_package(OpenCV REQUIRED core videoio)
#
#    If the module is found then OPENCV_<MODULE>_FOUND is set to TRUE.
#
#    This file will define the following variables:
#      - OpenCV_LIBS                     : The list of all imported targets for OpenCV modules.
#      - OpenCV_INCLUDE_DIRS             : The OpenCV include directories.
#      - OpenCV_ANDROID_NATIVE_API_LEVEL : Minimum required level of Android API.
#      - OpenCV_VERSION                  : The version of this OpenCV build: "4.5.4"
#      - OpenCV_VERSION_MAJOR            : Major version part of OpenCV_VERSION: "4"
#      - OpenCV_VERSION_MINOR            : Minor version part of OpenCV_VERSION: "5"
#      - OpenCV_VERSION_PATCH            : Patch version part of OpenCV_VERSION: "4"
#      - OpenCV_VERSION_STATUS           : Development status of this build: ""
#
# ===================================================================================

The code structure is as follows:

 Check the source code here: https://github.com/xiangang/AndroidDevelopmentPractices/tree/develop

Compilation problems encountered

Integrating OpenCV is simple, but sometimes requires a little luck. Like the author, luck is not very good, the following is the complete log of the compilation error.

FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':OpenCVMobile:buildCMakeDebug[armeabi-v7a]'.
> Build command failed.
  Error while executing process /home/xiangang/Android/Sdk/cmake/3.18.1/bin/ninja with arguments {-C /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/.cxx/Debug/4r2c6mo1/armeabi-v7a opencv_mobile}
  ninja: Entering directory `/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/.cxx/Debug/4r2c6mo1/armeabi-v7a'
  [1/1] Linking CXX shared library /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/build/intermediates/cxx/Debug/4r2c6mo1/obj/armeabi-v7a/libopencv_mobile.so
  FAILED: /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/build/intermediates/cxx/Debug/4r2c6mo1/obj/armeabi-v7a/libopencv_mobile.so 
  : && /work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=armv7-none-linux-androideabi23 --gcc-toolchain=/work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security   -frtti -fexceptions -fopenmp -static-openmp -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libopencv_mobile.so -o /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/build/intermediates/cxx/Debug/4r2c6mo1/obj/armeabi-v7a/libopencv_mobile.so CMakeFiles/opencv_mobile.dir/opencv_mobile.cpp.o  -landroid  /work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/23/liblog.so  -latomic -lm && :
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:23: error: undefined reference to 'cv::Mat::Mat(int, int, int, void*, unsigned int)'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:24: error: undefined reference to 'cv::Mat::Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:25: error: undefined reference to 'cv::cvtColor(cv::_InputArray const&, cv::_OutputArray const&, int, int)'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:53: error: undefined reference to 'cv::Mat::release()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:54: error: undefined reference to 'cv::Mat::release()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  clang++: error: linker command failed with exit code 1 (use -v to see invocation)
  ninja: build stopped: subcommand failed.
  


* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
==============================================================================

2: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':OpenCVMobile:buildCMakeRelWithDebInfo[armeabi-v7a]'.
> Build command failed.
  Error while executing process /home/xiangang/Android/Sdk/cmake/3.18.1/bin/ninja with arguments {-C /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/.cxx/RelWithDebInfo/442v101w/armeabi-v7a opencv_mobile}
  ninja: Entering directory `/work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/.cxx/RelWithDebInfo/442v101w/armeabi-v7a'
  [1/1] Linking CXX shared library /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/build/intermediates/cxx/RelWithDebInfo/442v101w/obj/armeabi-v7a/libopencv_mobile.so
  FAILED: /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/build/intermediates/cxx/RelWithDebInfo/442v101w/obj/armeabi-v7a/libopencv_mobile.so 
  : && /work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=armv7-none-linux-androideabi23 --gcc-toolchain=/work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security   -frtti -fexceptions -fopenmp -static-openmp -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libopencv_mobile.so -o /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/build/intermediates/cxx/RelWithDebInfo/442v101w/obj/armeabi-v7a/libopencv_mobile.so CMakeFiles/opencv_mobile.dir/opencv_mobile.cpp.o  -landroid  /work/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/23/liblog.so  -latomic -lm && :
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:23: error: undefined reference to 'cv::Mat::Mat(int, int, int, void*, unsigned int)'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:24: error: undefined reference to 'cv::Mat::Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:25: error: undefined reference to 'cv::cvtColor(cv::_InputArray const&, cv::_OutputArray const&, int, int)'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:53: error: undefined reference to 'cv::Mat::release()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:54: error: undefined reference to 'cv::Mat::release()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  /work/AndroidStudioProjects/AndroidDevelopmentPractices/AndroidJetpackComposeSample/OpenCVMobile/src/main/cpp/opencv_mobile.cpp:55: error: undefined reference to 'cv::Mat::~Mat()'
  clang++: error: linker command failed with exit code 1 (use -v to see invocation)
  ninja: build stopped: subcommand failed.
  


* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
==============================================================================

* Get more help at https://help.gradle.org

BUILD FAILED in 2s
72 actionable tasks: 4 executed, 68 up-to-date

The corresponding source code is as follows:

#include <jni.h>
#include <string>
#include "common.h"
#include <android/bitmap.h>
// for native window JNI
#include <android/native_window_jni.h>
#include <android/native_window.h>
// for native OpenCV JNI
#include "opencv2/core/core.hpp"
#include "opencv2/core/mat.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

extern "C"
JNIEXPORT void JNICALL
Java_com_nxg_opencv_OpenCVMobile_renderYuvDataOnSurface(JNIEnv *env, jclass clazz, jint width,
                                                        jint height, jbyteArray yuv_data,
                                                        jobject surface) {
    // yuv转rgba
    jbyte *data = env->GetByteArrayElements(yuv_data, nullptr);
    cv::Mat yuvImg(height + height / 2, width, CV_8UC1, data);
    cv::Mat rgbImg;
    cv::cvtColor(yuvImg, rgbImg, COLOR_YUV2RGBA_IYUV);
    // 这两行代码用于翻转的,用不到,这里注释掉
    //cv::transpose(yuvImg, rgbImg);
    //cv::flip(yuvImg, rgbImg, 1);
    //获取ANativeWindow
    ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    ANativeWindow_acquire(window);
    //设置ANativeWindow相关参数,包括宽/高/像素格式
    ANativeWindow_setBuffersGeometry(window, rgbImg.cols, rgbImg.rows, WINDOW_FORMAT_RGBA_8888);
    ANativeWindow_Buffer outBuffer;
    // 调用ANativeWindow_lock锁定后台的缓冲部分,并获取surface缓冲区的地址
    if (int32_t err = ANativeWindow_lock(window, &outBuffer, nullptr)) {
        LOGE("ANativeWindow_lock failed with error code: %d\n", err);
        ANativeWindow_release(window);
    }
    // 拷贝rgb数据到缓冲区
    auto *outPtr = reinterpret_cast<uint8_t *>(outBuffer.bits);
    int dst_line_size = outBuffer.stride * 4;
    //一行一行拷贝
    for (int i = 0; i < outBuffer.height; ++i) {
        //从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
        memcpy(outPtr + i * dst_line_size, rgbImg.data + i * rgbImg.cols * 4, dst_line_size);
    }
    //绘制
    ANativeWindow_unlockAndPost(window);
    //用完释放
    ANativeWindow_release(window);
    env->ReleaseByteArrayElements(yuv_data, data, 0);
    yuvImg.release();
    rgbImg.release();
}

Simple code, how can something go wrong? Checked the header files, yes. Source code, yes. Then there is only one possibility, CMake compiles a problem. Looking back at the key CMake code for integrating OpenCV:

set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv/sdk/native/jni)
find_package(OpenCV 4.5.4 REQUIRED core features2d highgui imgproc photo video)
message("OpenCV_DIR is ${OpenCV_DIR}")
message("OpenCV_FOUND is ${OpenCV_FOUND}")
message("OpenCV_LIBS is ${OpenCV_LIBS}")
target_link_libraries( # Specifies the target library.
        opencv_mobile
        ${OpenCV_LIBS}
        # Links the target library to the log library
        # included in the NDK.
        android
        ${log-lib})

Added printing of key variables. Finally, it was found that the OpenCV_LIBS variable is empty, no wonder there is a problem.

Then look at where OpenCVConfig.cmake assigns OpenCV_LIBS, and continue to print in key places as follows:

 It was found that it was not implemented here at all. Continue to check up. Finally, it was found that the red box in the figure below returned early. The reason is that the version of Android used for compilation is lower than the version defined by OpenCV_ANDROID_NATIVE_API_LEVEL. So far, the truth is revealed!

Now that you know the reason, it's easy to handle.

Solution

Modify minSdkVersion

If the project has no restrictions, directly change the minSdkVersion of the corresponding module's build.gralde to the same version as OpenCV_ANDROID_NATIVE_API_LEVEL, and recompile.

android {
    compileSdk = BuildConfig.compileSdk
    defaultConfig {
        minSdk = 24
        targetSdk = BuildConfig.targetSdkVersion
        testInstrumentationRunner = BuildConfig.testInstrumentationRunner
        consumerProguardFiles("consumer-rules.pro")
    }
}

Modify OpenCV_ANDROID_NATIVE_API_LEVEL

You may think, can I directly change OpenCV_ANDROID_NATIVE_API_LEVEL? For example, in my project, minSdkVersion=23, the value of OpenCV_ANDROID_NATIVE_API_LEVEL is 24, can I directly change OpenCV_ANDROID_NATIVE_API_LEVEL to 23?

The author's actual test found that it is possible, but whether there are other unknown problems is unknown. This method is not very recommended. It is reasonable to believe that OpenVC requires such a thing.

Guess you like

Origin blog.csdn.net/xiangang12202/article/details/129979330