4

如何编译iOS版OpenCV动态库

 2 years ago
source link: https://xnxy.github.io/2020/05/11/%E5%A6%82%E4%BD%95%E7%BC%96%E8%AF%91iOS%E7%89%88OpenCV%E5%8A%A8%E6%80%81%E5%BA%93/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Overview

OpenCV的编译动态库单独拎出来写这篇博客,主要是因为根据官方的教程编译出来的动态库将可执行程序内部的install Name写死了,导致动态库无法链接到,报dyld: Library not loaded:错误。

GitHubOpenCV库的issues上也有人提,但并没有得到解决。

而它打包用的是cmake,自己也不想去修改他的Python脚本cmake文件,于是使用了install_name_tool工具修改OpenCV二进制文件中的链接路径,完美地解决了该问题。

于是将其记录下来,以便后期查阅。

使用脚本直接打包OpenCV动态库,添加到项目中会报下方错误:

dyld: Library not loaded: /Users/cntp/Documents/opencv-4.1.0/platforms/ios/ios/build/build-iphonesimulator/lib/Release/opencv2.framework/opencv2

Referenced from: /private/var/containers/Bundle/Application/UUID/MyApp.app/Frameworks/MyApp.framework/MyApp
Reason: image not found

使用otool工具查看,会发现二进制文件中将链接路径写成固定路径:

cntp@TPL-0000-161520deMacBook-Pro opencv2.framework % otool -L opencv2
opencv2:
/Users/cntp/Documents/opencv-4.1.0/platforms/ios/ios/build/build-iphonesimulator/lib/Release/opencv2.framework/opencv2 (compatibility version 4.1.0, current version 4.1.0)

关于Opencv

OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。

主要模块分为以下几种:

  • core:简洁核心模块,基本函数,基本数据结构;
  • imgproc:图像处理模块,线性和非线性图像滤波,几何图像转换,颜色空间转换,直方图等;
  • video:视频分析模块,运动估计,背景消除,物体跟踪算法;
  • calib3d:基本多视角几何算法,单体和立体相机的标定,对象姿势估计,双目立体匹配算法和元素的三维重建;
  • features2d:包含了显著特征检测算法,描述算子和算子匹配算法;
  • objdetect:物体检测和一些预定义的物体的检测(如人脸,眼睛,杯子,人,汽车等);
  • ml:多种机器学习算法,如K均值,支持向量机和神经网络;
  • highgui:简单易用接口,有视频捕捉,图像和视频编码功能,简单UI接口,iOS的是其中一个子集;
  • gpu:GPU加速算法,iOS不可用;
  • ocl:OpenCL通用算法,iOS不可用;
  • 其它,辅助、算法等。

OpenCV可用于解决如下领域问题:

关于Cmake

OpenCV使用Cmake工具进行编译的,所以在打包Framework之前我们也需要了解Cmake

CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。具体内容可以查看百度百科关于Cmake的介绍

同时也可以查看CMake官网

CMake是旨在构建,测试和打包软件的开源,跨平台工具系列。
CMake用于使用简单平台和独立于编译器的配置文件来控制软件编译过程,并生成可在您选择的编译器环境中使用的本机makefile和工作区。
CMake工具套件是由Kitware创建的,旨在满足ITK和VTK等开源项目对功能强大的跨平台构建环境的需求。

---

CMake is an open-source, cross-platform family of tools designed to build, test and package software.
CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice.
The suite of CMake tools were created by Kitware in response to the need for a powerful, cross-platform build environment for open-source projects such as ITK and VTK.

第一步:查看是否安装Cmake

如果想在Mac上编译OpenCV,需要检测Mac中是否安装过Cmake

对于如何查看,我们可以直接在终端输入cmake --version,如果有相应版本会出现下方内容:

cntp@TPL-0000-161520deMacBook-Pro ~ % Cmake --version
cmake version 3.17.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).

如果出现-bash: cmake: command not found则代表电脑中并没有安装Cmake

如果没有安装Cmake可以通过Homebrew进行安装,具体命令如下:

brew install cmake

其中Homebrew是Mac OS平台下的软件包管理工具,大家应该都不陌生,具体的使用可以查看Homebrew官网

安装完成后即可编译OpenCV动态库

第二步:编译OpenCV动态库

下载相应版本的OpenCVcd~/platforms/ios目录,我们可以看到其打包的脚本build_framework.py,语言是Python并不是常用的Shell脚本,不过语言很简单。

如果项目中需要静态库,可以直接到opencv官网下载,或者直接使用python build_framework.py ios,其中ios为编译文件的路径,最后会在ios下看到opencv2.framework

如果需要编译动态库需要在后面添加--dynamic,或者到python脚本中将parser.add_argument('--dynamic', default=False, action='store_true', help='build dynamic framework (default is "False" - builds static framework)')中的default改为true

打包动态库的命令如下:

cd /Users/cntp/Documents/opencv-4.1.0/platforms/ios 

python build_framework.py ios --dynamic

编译时间会比较长,结束后会在/Users/cntp/Documents/opencv-4.1.0/platforms/ios/ios目录下得到相应的opencv2.framework

ps:不用吐槽ios不是iOS,它那边文档就是这样写的,也就这样用了。

第三步:修改OpenCV二进制文件中的链接地址

理论上到这一步就可以了,直接将opencv2.framework添加到外面工程中,修改EmbedEmbed&Sign就可以。

但当在运行时加载opencv.framework时,它会直接报错,由终端的打印日志可以看出app链接的路径为打包存放的默认路径,也就是/Users/cntp/Documents/opencv-4.1.0/platforms/ios/ios

我们可以使用otool工具进行查看,命令如下:

cntp@TPL-0000-161520deMacBook-Pro opencv2.framework % otool -L opencv2
opencv2:
/Users/cntp/Documents/opencv-4.1.0/platforms/ios/ios/build/build-iphonesimulator/lib/Release/opencv2.framework/opencv2 (compatibility version 4.1.0, current version 4.1.0)
/System/Library/Frameworks/Accelerate.framework/Accelerate (compatibility version 1.0.0, current version 4.0.0)
/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 1251.12.0)
/System/Library/Frameworks/QuartzCore.framework/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
/System/Library/Frameworks/AssetsLibrary.framework/AssetsLibrary (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 61000.0.0)
/System/Library/Frameworks/AVFoundation.framework/AVFoundation (compatibility version 1.0.0, current version 2.0.0)
/System/Library/Frameworks/CoreImage.framework/CoreImage (compatibility version 1.0.0, current version 5.0.0)
/System/Library/Frameworks/CoreMedia.framework/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/CoreVideo.framework/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1570.15.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1570.15.0)
/usr/lib/libc++abi.dylib (compatibility version 1.0.0, current version 400.17.0)

我们可以看到链接opencv2.framework/opencv2的路径(install Name)是写死的。

而正确的动态库的链接路径(install Name)应该是@rpath/opencv2.framework/opencv2

知道这一点后我们使用install_name_tool工具修改它的链接路径即可,我们可以将它写死的链接路径(install Name)修改成@rpath/opencv2.framework/opencv2,具体操作如下:

cntp@TPL-0000-161520deMacBook-Pro opencv2.framework % install_name_tool h
Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool [-change old new] ... [-rpath old new] ... [-add_rpath new] ... [-delete_rpath old] ... [-id name] input
cntp@TPL-0000-161520deMacBook-Pro opencv2.framework % install_name_tool -id @rpath/opencv2.framework/opencv2 opencv2
cntp@TPL-0000-161520deMacBook-Pro opencv2.framework % otool -L opencv2
opencv2:
@rpath/opencv2.framework/opencv2 (compatibility version 4.1.0, current version 4.1.0)
/System/Library/Frameworks/Accelerate.framework/Accelerate (compatibility version 1.0.0, current version 4.0.0)
/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 1251.12.0)
/System/Library/Frameworks/QuartzCore.framework/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
/System/Library/Frameworks/AssetsLibrary.framework/AssetsLibrary (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 61000.0.0)
/System/Library/Frameworks/AVFoundation.framework/AVFoundation (compatibility version 1.0.0, current version 2.0.0)
/System/Library/Frameworks/CoreImage.framework/CoreImage (compatibility version 1.0.0, current version 5.0.0)
/System/Library/Frameworks/CoreMedia.framework/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/CoreVideo.framework/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1570.15.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1570.15.0)
/usr/lib/libc++abi.dylib (compatibility version 1.0.0, current version 400.17.0)
cntp@TPL-0000-161520deMacBook-Pro opencv2.framework %

使用install_name_tool h查看所有指令,根据提示使用install_name_tool -id @rpath/opencv2.framework/opencv2 opencv2修改其链接路径(install Name)。

可以再使用otool工具验证一下,发现没有问题,然后再将其添加到项目中,因为是动态库,修改EmbedEmbed&Sign运行、使用同样没有问题。

至此问题完美解决。

关于@rpath、@loader_path、@executable_path

Framework工程的TARGETS->Build Settings中的Linking可以看到Dynamic Library Install NameDynamic Library Install Name BaseRunpath Search Paths等配置,根据其名称可以大致了解其含义。

这里先梳理下几个单词的概念。

install Name

install Name可以理解为安装名称,本质上是一个相对路径,主要是告诉链接器(linker synthesized)在运行时从哪调用需要的库。

就比如刚刚编译的动态库opencv2.framework,在编译的时候会被拷贝到应用程序(**.app)下的Frameworks目录下,其二进制文件的绝对路径地址大致为~/-.app/Frameworks/opencv2.framework/opencv2,其中install Name就是@rpath/opencv2.framework/opencv2

当动态链接器需要opencv2.framework的时候,它就会从应用程序中根据install Name找到opencv2.framework

@rpath

在维基百科中有关于rpath的介绍:

In computing, rpath designates the run-time search path hard-coded in an executable file or library. Dynamic linking loaders use the rpath to find required libraries.

Specifically, it encodes a path to shared libraries into the header of an executable (or another shared library). This RPATH header value (so named in the Executable and Linkable Format header standards) may either override or supplement the system default dynamic linking search paths.

翻译过来就是:

在计算中 rpath指定在可执行文件或库中硬编码的运行时 搜索路径。动态链接加载程序时使用rpath查找所需的库。

具体来说,它将共享库的路径编码为可执行文件(或另一个共享库)的标头。此RPATH标头值(在“ 可执行文件和链接格式”标头标准中如此命名)可以替代或补充系统默认的动态链接搜索路径。

其解释已经十分详细了,我们可以理解为@rpath就是一个相对路径。

其中@rpath/opencv2.framework/opencv2就相当于我们项目下动态库所在的位置~/**.app/Frameworks/opencv2.framework/opencv2

@loader_path

@loader_pathFramework工程中TARGETS -> Build Settings -> Linking -> Runpath Search Paths的一项配置,字面上的意思是加载路径。

其实也就是Framework加载的路径,比如app下的动态库opencv2.framework@loader_path则相当于~/**.app/Frameworks/opencv2.framework

@executable_path

@executable_pathFramework工程中TARGETS -> Build Settings -> Linking -> Runpath Search Paths的一项配置,字面上的意思是可执行文件路径。

@loader_path不同的是@executable_path代表的是可执行文件(mach-o)的路径。还以app下加载动态库opencv2.framework为例,其@executable_path则相当于~/**.app/Frameworks/opencv2.framework/opencv2

ps:写完关于@rpath、@loader_path、@executable_path本来还想将程序如何链接动态库、静态库写一下,最后还是决定单独拎出来写。

同时准备将动、静态库相互依赖;编译打包动、静态库;等注意事项整理下。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK