Mac dylib动态库加载路径问题(以OpenCV为例)

在自己的Mac上写了一个基于OpenCV的简单程序;需要传给其他人共同调试,但是可执行文件在他人的Mac上无法运行;执行时会提示:

dyld: Library not loaded: /usr/local/Cellar/opencv/2.4.12/lib/libopencv_features2d.2.4.dylib

这样就引申出来一个问题:在xcode下编译出的程序,在开发机器上运行是没有问题的。但是给其他用户用,就可能出问题。因为用户不一定有这个库。
有两种方法可以解决这个问题;一是给其他用户也安装依赖的库文件;二是将所有的dylib随行发布,消除依赖。
第一种方案不考虑,大部分时候这样做并不现实;下面说说如何随行发布dylib。

单纯将依赖的dylib文件拷贝到可执行文件目录下一同传输过去是不能消除依赖的;执行的时候还是报错;
在编译一个动态库的时候, 你需要指定 INSTALL_PATH. 也就是它的安装路径;编译完成后如果一个可执行程序使用了该动态库, 那么在编译可执行程序的时候, 动态库的 INSTALL_PATH 会被记录到可执行程序中, 用来定位这个动态库。

因此我们首先需要将用到的dylib文件都拷贝到可执行文件目录下,然后改变动态库的INSTALL_PATH;将其改到可执行文件所在目录;
需要注意的是:如果依赖多个动态库,用到的动态库已会依赖其他动态库,因此用到的所有的动态库的依赖动态库路径都需要修改。

以OpenCV为例子,假设最终编译出来的可执行文件为 macimgproc;执行命令:otool -L macimgproc可看到如下的输出:

macimgproc:
    /usr/local/opt/opencv/lib/libopencv_calib3d.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_contrib.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_core.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_features2d.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_flann.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_gpu.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_highgui.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_imgproc.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_legacy.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_ml.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_nonfree.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_objdetect.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_ocl.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_photo.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_stitching.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_superres.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_video.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_videostab.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 307.4.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)

说明macimgproc依赖所有的OpenCV动态库文件;因此首先需要将所有动态库文件拷贝到macimgproc所在目录,然后需要将macimgproc文件中的所有/usr/local/opt/opencv/lib/libopencv_xxx修改为@executable_path/libopencv_xxx

@executable_path表示可执行文件所在目录;指示所有OpenCV动态库从可执行文件所在目录查找;
更多@executable_path的介绍以及其他变量参见文章 @rpath, @loader_path, @executable_path
使用命令install_name_tool -change {old.dylib} {new.dylib} {filename}修改动态库的INSTALL_PATH,例如:

install_name_tool -change /usr/local/Cellar/opencv/2.4.12/lib/libopencv_flann.2.4.dylib @executable_path/libopencv_flann.2.4.dylib macimgproc

执行后重新otool -L macimgproc可看到如下的输出:

macimgproc:
    ...
    /usr/local/opt/opencv/lib/libopencv_features2d.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    @executable_path/libopencv_flann.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    /usr/local/opt/opencv/lib/libopencv_gpu.2.4.dylib (compatibility version 2.4.0, current version 2.4.12)
    ...

依次修改所有依赖即可。

整个OpenCV库大概有19个dylib文件,因此写了一个简单的批量修改脚本:

#!/usr/bin/ruby

Preview=0

def fix_opencv_lib_link(file,rlib)
    if(rlib.include?('libopencv'))
        name = rlib.split('/').last
        cmd = "install_name_tool -change #{rlib} @executable_path/#{name} #{file}"
        if Preview == 1
            puts "Preivew: #{cmd}"
        else
            `#{cmd}`
        end
    else 
        puts "ignore rlib: #{rlib}";
    end
end

def fix_file_rely_lib(file)
  puts "===============start change #{file}==============="
  linklibs = `otool -L #{file}`.split("\n")
  linklibs.delete_at(0)
  linklibs.each_with_index do |rlib,i|
    rlib = rlib.split()[0]
    fix_opencv_lib_link(file,rlib)
  end
end

def doopencvlist
  # puts "Preview: #{Preview}"
  `ls |grep libopencv`.split().each_with_index do |file,i|
    fix_file_rely_lib(file)
  end
end

def viewlib(file)
    puts `otool -L #{file}`
end

if __FILE__ == $0
  if ARGV[0] == 'preview'
    Preview = 1;
    doopencvlist();
  elsif ARGV[0] == 'view'
    `ls |grep libopencv`.split().each_with_index do |file,i|
      # puts "===============start view #{file}==============="
      viewlib(file)
    end
  elsif ARGV[0] == 'do'
    doopencvlist();
  elsif ARGV[0] == 'previewfile'
    Preview = 1;
    fix_file_rely_lib(ARGV[1])
  elsif ARGV[0] == 'file'
    fix_file_rely_lib(ARGV[1])
  else
    puts "please input command [preview,do,previewfile,file,view] "
  end
end

参考链接

http://blog.csdn.net/openglnewbee/article/details/17783909
如何使用第三方的dylib
@rpath, @loader_path, @executable_path
Apple Developer:Overview of Dynamic Libraries
Apple Developer: Run-Path Dependent Libraries

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 仅以方便自己查阅记录前言1.静态库和动态库有什么异同?静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗...
    190CM阅读 4,170评论 0 4
  • 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别...
    吃瓜群众呀阅读 11,872评论 3 42
  • 原文地址 ,此简书只做备份,强烈推荐原文,毕竟格式比简书好看,还清晰 起因 去年,链家网iOS端,之前由于所有的业...
    南栀倾寒阅读 12,255评论 29 130
  • 一个人陪伴另一个人是缘分,也是一种幸福。而我希望你们幸福。 01 刚得知他们分手的消息,我是不相信的,我以为她在和...
    荧火虫和土豆阅读 323评论 0 0
  • /小雨文图 十月,我来到这片湖 没有人告诉我它的名字 我暂且叫它未名湖 我只是偶然经过,不作停留 水在水里,岸在岸...
    小雨飘飘阅读 338评论 0 1