- 1.搜索顺序
- 2.和应用程序一同发布
因为运行时动态库的搜索路径的先后顺序是: a.编译目标代码时指定的动态库搜索路径; b.环境变量LD_LIBRARY_PATH指定的动态库搜索路径; c.配置文件/etc/ld.so.conf中指定的动态库搜索路径; d.默认的动态库搜索路径/lib和/usr/lib; /lib和/usr/lib只有root权限才可以修改,配置文件/etc/ld.so.conf也需要root权限。
2.和应用程序一同发布在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
合理的脚本代码可以有效的提高工作效率,减少重复劳动。