天天看点

Android Studio CMake 引入静态包.a 以OpenCV为例

以OpenCV为例,记录开发过程并附上部分踩坑细节

1.引入openCV的.a包,官方SDK目录如下:

Android Studio CMake 引入静态包.a 以OpenCV为例

记得第三方也要引入。引入后的样子如下:

Android Studio CMake 引入静态包.a 以OpenCV为例

你会发现,x86和arm的包不太一样。

2.引入OpenCV头文件.h .hpp

首先,在你的cpp/include下,加入openCV的头文件,如下图:

Android Studio CMake 引入静态包.a 以OpenCV为例

官方SDK在这里:

Android Studio CMake 引入静态包.a 以OpenCV为例

3.CMake引入.a及你自己的c++源码

先引入头文件:

set(libs ${CMAKE_SOURCE_DIR}/..)
include_directories(${libs}/cpp/include/opencv2)
set(target xxx) # 打包的名字
           

cmake语法就不在这里赘述了。。。

上面一堆.a文件,一个个引入,引入的写法在下面:(以最重要的core为例)

add_library(core STATIC IMPORTED)
set_target_properties(core
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_core.a)
           

最终呈现的链接库是这样的:

Android Studio CMake 引入静态包.a 以OpenCV为例

带劲不。。。

踩坑记录:

1.报zlib的错误,缺少gzputs相关的,open、close什么的。undefined symbol: gzputs

解决方案:

CMake加 find_package(ZLIB)

链接库加 ZLIB::ZLIB

参考:https://stackoverflow.com/questions/53298492/how-to-link-zlib-with-cmake/56886808

2.报AMedia相关的错误。undefined symbol: AMediaExtractor_new

解决方案:

链接库加 mediandk

如果还遇到错误,参考:https://stackoverflow.com/questions/45251937/mediandk-undefined-reference-to-amediacodec-signalendofinputstream

3.报openCV相关错误。undefined reference to 'cv::waitKey(int)'

这个比较草蛋(一种蛋)。。。明明官方的.a文件都引入了。

搜了下资料原来是编译顺序的问题,C++与Java不一样。

你需要在链接库的时候,把最核心的core,放到最后,最起码放到报错的imgproc这些后面:

Android Studio CMake 引入静态包.a 以OpenCV为例

参考:https://answers.opencv.org/question/186124/undefined-reference-to-cvsoftdoubleoperator/

4.报不知名错误:  ld: error: undefined symbol: __write_chk

原因是NDK版本不一致,你当前编辑器的NDK版本与.a的不一致。

解决方案:

(1)尝试降低/升高你的NDK版本。(参考了https://blog.csdn.net/printf123scanf/article/details/106136741)

(2)拿源码重新编译你当前版本NDK的.a静态库。

后一个方案适合大佬,我不是别问我怎么编译。。。问C++造轮子的工程师,他们很熟悉。

关于如何正确改变NDK版本我也给你找好了:(图出自:https://stackoverflow.com/questions/66540676/invalid-revision-3-18-1-cmake-in-android-studio)

Android Studio CMake 引入静态包.a 以OpenCV为例

cmake换成NDK,那个“-”别乱点,如果点乱了确定会给你提示,点cancel重来哈。别怪我没提醒你。。。(擦眼泪)

记得build.gradle也要改哈:ndkVersion = 'yours'

5.差不多能跑起来了,,,会报一个x86的错误。

解决方案:

在gradle的defaultConfig里加

ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
           

arm就够你用了。。。如果真有x86需求的话,上面就说了openCV针对x86的指令集做了兼容,那么你的CMake就需要兼容,咋兼容等我有这个需求了再补充哈。(狗头保命)

声明一下这边是:opencv2,so包是libopencv_java4.so

一般情况下这种知名的第三方都不会随便改的,所以一般是NDK19。

在开发过程中,高版本的NDK会让你兼容,在gradle的cmake加 arguments "-DANDROID_STL=c++_shared"。

这样的话,编译动态库会有libc++.so,更换19可以去掉,这样就只打一个so包了。

每个人因为环境代码不同肯定会遇到不同的问题,本篇文章不一定能解决您全部的问题。

但尽管如此,我也掉了好多头发。。。我本可以不分享出来的,生活不易,希望能让国内的开发者少走弯路。

故,侵究。