使用CMake(Android NDK环境)编译OpenCV摄像头程序出现链接错误,常规命令行编译正常
解决Android NDK CMake交叉编译OpenCV的链接错误问题
看起来你踩了两个关键的坑:编译参数错误和平台不兼容的库链接,这也是交叉编译时很容易犯的问题。咱们一步步来解决:
1. 先修复build脚本里的低级错误
你脚本里的STD=-std=c++11 -o是明显错误的:-o是编译器指定输出文件的参数,不属于编译flags的范畴,CMake会自动处理目标输出,所以必须把-o去掉。另外,脚本没有指定构建目录,导致CMake警告“无源码/二进制目录”,最好指定单独的构建目录(比如build)避免污染源码目录。
修正后的create_makefile.sh:
#!/bin/bash SDK=/Users/David/Library/Android/sdk CMAKE=$SDK/cmake/3.18.1/bin/cmake NDK=$SDK/ndk/23.0.7272597 TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake ABI=arm64-v8a MIN_SDK=30 # 注意:你用的是android30的编译器,MIN_SDK要和这个版本匹配,之前的16会不兼容 STL=c++_shared STD=-std=c++11 CXX=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android30-clang++ export CXX=$CXX # 指定build目录作为构建输出,避免混乱 $CMAKE -B build \ -DCMAKE_CXX_FLAGS="$STD" \ -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE \ -DANDROID_ABI=$ABI \ -DANDROID_NATIVE_API_LEVEL=$MIN_SDK \ -DANDROID_STL=$STL
2. 核心问题:你在链接Mac平台的OpenCV库
这是导致链接错误(找不到cv::VideoCapture等符号)的根本原因:你用Android NDK交叉编译arm64-v8a架构的二进制,但find_package指向的是Homebrew安装的Mac x86_64版OpenCV,两个平台的库二进制不兼容,自然无法链接。
你需要用Android平台的OpenCV库,有两种方案:
方案A:使用预编译的Android OpenCV SDK
- 从OpenCV官网下载对应版本的Android SDK(比如OpenCV 4.5.2 Android SDK)
- 解压后,找到SDK内的
sdk/native/jni目录,这是CMake可以识别的OpenCV配置目录 - 修改CMakeLists.txt里的
OpenCV_DIR为这个路径:set(OpenCV_DIR "/path/to/your/opencv-android-sdk/sdk/native/jni")
方案B:交叉编译OpenCV for Android
如果需要自定义OpenCV的编译选项,可以自己用NDK工具链编译OpenCV源码:
- 克隆OpenCV官方源码仓库
- 用类似你现在的build脚本,指定NDK工具链,编译生成arm64-v8a架构的OpenCV库
- 在你的项目CMakeLists.txt中指向编译后的OpenCV安装目录
3. 修复CMakeLists.txt的遗漏
你只给动态库shared_library_cpp链接了OpenCV,但可执行文件cpp_exec没有链接!这也是导致链接错误的原因之一,必须给所有用到OpenCV的目标添加链接。同时,去掉无用的Xcode签名属性(你是编译Android目标,这个属性无效)。
修正后的CMakeLists.txt:
cmake_minimum_required(VERSION 3.7 FATAL_ERROR) project(shared_library_cpp VERSION 1.0.0 LANGUAGES CXX) # 替换为Android版OpenCV的jni目录路径 set(OpenCV_DIR "/path/to/opencv-android-sdk/sdk/native/jni") find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) # 动态库目标 add_library(shared_library_cpp SHARED lib_cpp.cpp cpp.def) target_link_libraries(shared_library_cpp ${OpenCV_LIBS}) # 可执行文件目标:必须链接OpenCV! add_executable(cpp_exec lib_cpp.cpp) target_link_libraries(cpp_exec ${OpenCV_LIBS}) set_target_properties(shared_library_cpp PROPERTIES PUBLIC_HEADER lib_cpp.h VERSION ${PROJECT_VERSION} SOVERSION 1 OUTPUT_NAME "cpp" )
4. 额外注意事项
- 确保
MIN_SDK和你使用的编译器版本匹配(比如你用aarch64-linux-android30-clang++,MIN_SDK就设为30),否则会出现API级别不兼容的问题 - 如果只是想在Mac本地编译运行程序,不需要用NDK的CMake,直接用Homebrew安装的本地CMake即可,此时链接本地OpenCV是正常的
内容的提问来源于stack exchange,提问作者Ludwig12
相关产品推荐
相关产品推荐

