如何在适用于 Android 和 iOS 的 C++ 跨平台库中正确链接 OpenCV?

Posted

技术标签:

【中文标题】如何在适用于 Android 和 iOS 的 C++ 跨平台库中正确链接 OpenCV?【英文标题】:How to properly link OpenCV in a C++ cross-platform library for Android and iOS? 【发布时间】:2021-06-26 04:45:37 【问题描述】:

我正在开发一个 C++ 库,包括 OpenCV,它将通过包装器和 NuGet 打包系统用于跨平台 Xamarin 解决方案(请参阅此guide)。我配置了一个 CMakeLists.txt 文件,但我根本无法正确链接静态 (ios) 和动态 (android) 库的 OpenCV。

我尝试更改 OpenCV_DIR 变量,从源代码安装和构建 OpenCV 并手动包含 OpenCV_INCLUDE_DIRS 变量的内容,但没有任何效果。我还注意到,仅使用 cv::Point 时,链接才有效。但是使用cv::Mat时链接不起作用,我不明白原因。

以下是我正在使用的CMakeLists.txt

cmake_minimum_required (VERSION 3.2)
project (MyLib C CXX)
enable_testing()

set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -std=c++11")
MESSAGE(STATUS "CMAKE_CXX_FLAGS: " $CMAKE_CXX_FLAGS)

# Source and headers files
set(SOURCES File1.cpp File2.cpp)
set(HEADERS File1.h File2.h)

# Library
if(BUILD_SHARED_LIBS)
  add_library (MyLib SHARED $SOURCES $HEADERS)
  target_compile_definitions(MyLib PUBLIC IS_BUILDING_SHARED)
else()
  add_library (MyLib STATIC $SOURCES $HEADERS)
endif()

# Dependencies
set(OpenCV_DIR /usr/local/Cellar/opencv/4.5.0_1/lib/cmake/opencv4)
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV_INCLUDE_DIRS = $OpenCV_INCLUDE_DIRS")
message(STATUS "OpenCV_LIBS = $OpenCV_LIBS")
message(STATUS "OpenCV_DIR = $OpenCV_DIR")
include_directories($OpenCV_INCLUDE_DIRS)
target_link_libraries(MyLib $OpenCV_LIBS)

以下显示了在构建过程中使用的 OpenCV 文件的位置。一切似乎都很好。

-- OpenCV_INCLUDE_DIRS = /usr/local/Cellar/opencv/4.5.0_1/include/opencv4
-- OpenCV_LIBS = opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_alphamat;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dnn_objdetect;opencv_dnn_superres;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hfs;opencv_img_hash;opencv_intensity_transform;opencv_line_descriptor;opencv_mcc;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_quality;opencv_rapid;opencv_reg;opencv_rgbd;opencv_saliency;opencv_sfm;opencv_shape;opencv_stereo;opencv_structured_light;opencv_superres;opencv_surface_matching;opencv_text;opencv_tracking;opencv_videostab;opencv_viz;opencv_xfeatures2d;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto
-- OpenCV_DIR = /usr/local/Cellar/opencv/4.5.0_1/lib/cmake/opencv4

安卓

以下是我用来构建 Android 动态库 (.so) 的命令。我已经安装了 NDK,并且正在为每个 ABI(x86、x86_64、armeabi-v7a、arm64-v8a)构建。

cmake ../.. -DCMAKE_TOOLCHAIN_FILE=/Users/$USER/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=21 -DANDROID_ABI=$abi_name -DBUILD_SHARED_LIBS=ON
cmake --build . --config Release

我在构建以下库时直接出错。

ld: error: /usr/local/Cellar/opencv/4.5.0_1/lib/libopencv_gapi.4.5.0.dylib: unknown file type
ld: error: /usr/local/Cellar/opencv/4.5.0_1/lib/libopencv_stitching.4.5.0.dylib: unknown file type
[...]
ld: error: /usr/local/Cellar/opencv/4.5.0_1/lib/libopencv_rapid.4.5.0.dylib: unknown file type
ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

iOS

以下是我用来构建 iOS 静态库 (.a) 的命令。我正在使用来自 repository 的 leetal 的 cmake 工具链文件。

cmake ../.. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../../ios.toolchain.cmake -DPLATFORM=OS64COMBINED -DBUILD_SHARED_LIBS=OFF
cmake --build . --config Release

静态库的编译似乎可以工作,因为没有打印错误消息。但是在最终的Xamarin解决方案中使用该库时,无法找到链接的库,并显示如下错误。

Native linking failed, undefined symbol: cv::Mat::deallocate(). Please verify that all the necessary frameworks have been referenced and native libraries are properly linked in. (MT5210)

问题

为了正确编译 OpenCV 并将其链接到我的 C++ 库中,我缺少什么?

我正在开发 macOS Big Sur 并使用以下工具版本:

cmake : 3.20.0-rc5 ndk : 23.0.7196353 苹果铿锵声:12.0.0

我希望我的问题描述足够清楚,我提前感谢您的帮助。

【问题讨论】:

Android:您需要链接为 Android 构建的 OpenCV 库,而不是为您的主机构建的库。 iOS:静态库不携带与其他库的依赖关系。与静态库链接时,您也需要链接其依赖项。 这里是如何使用预建库的示例***.com/a/64433504/5130269 可能会有所帮助。 感谢您的回复。 @Tsyvarev 我下载了适用于 Android 的 OpenCV,将 OpenCV_DIR 设置为 jni 文件夹,并将每个 ABI 的目标与 libopencv_java4.so 链接起来。编译/链接有效,但 Xamarin 无法加载库 (null)。这些变化是否正确?还有什么我错过的吗? 【参考方案1】:

我们遇到了同样的问题,包括 Xamarin 的 DllNotFoundException 以及来自上次评论的消息,这让我想到了这个话题。最后为我们解决的异常是静态链接到 OpenCV *.a 库,而不是链接到共享的 libopencv_java4.so 文件。所以我们现在在构建输出中为每个 android ABI 提供了一个巨大的 30MB nativelib.so 文件,而不是每个 ABI 的一对小的 nativelib.so 和 libopencv_java4.so。 CMakeLists 看起来像这样:

set( OpenCV_DIR "~/opencv/build/OpenCV-android-sdk/sdk/native/jni" )
find_package( OpenCV REQUIRED )
    
target_link_libraries( # Specifies the target library.
                           nativelib
                           $OpenCV_LIBS)

我们项目中的另一件事是我们使用 OpenCV 可选模块并且必须创建一个自定义 OpenCV 构建,我想这可以确保我们的本机库和 OpenCV 针对相同的 NDK 版本进行编译。我想使用预构建的 OpenCV 发行版并针对不同的 NDK 版本进行编译也可能会导致问题。

【讨论】:

以上是关于如何在适用于 Android 和 iOS 的 C++ 跨平台库中正确链接 OpenCV?的主要内容,如果未能解决你的问题,请参考以下文章

如何在适用于 Android 和 iOS 的 C++ 跨平台库中正确链接 OpenCV?

适用于 Android 和 iOS 的基于 websocket 的 MQTT

适用于 Android 和 iOS 应用程序的 Firebase

Xamarin.Forms - 适用于 iOS 和 Android 的推送通知

适用于 iOS/Android 的 AWS 移动开发工具包中内置的网络安全性如何?

我已经下载了 Visual Studio Community 2013。但我没有找到适用于 android 和 ios 应用程序的选项。