打包之后,在测试电脑安装后,程序需无法运行,错误信息为:找不到依赖的动态链接库
试想动态链接库的问题,我们在 Windows 是怎么处理的呢?拷贝到执行文件相同目录或系统 system32
目录即可。苹果的 app 与 Windows 的可执行文件有一定的区别,Mac 下的 app 不是一个可执行文件,而是一个目录,而真正的可执行文件是在 xxx.app/Contents/MacOS/
目录下;
于是我将动态库做了如下的操作:
- 拷贝到 app 的可执行文件相同的目录下,即
xxx.app/Contents/MacOS/
目录下; - 拷贝到
xxx.app/Contents/Frameworks/
目录下,而我检查Xcode
工程目录的Runpath Search Paths
的属性,默认的就是$(inherited) @executable_path/../Frameworks
;
以上的操作均不能解决问题,于是我就使用 otool -L xxx.dylib
命令来查看依赖库的情况,如下:
libtimelink-tuio.dylib:
/usr/local/lib/libtinyxml.dylib (compatibility version 1.0.0, current version 1.0.0)
libboost_thread.dylib (compatibility version 0.0.0, current version 0.0.0)
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
/usr/local/lib/libtimelink-tuio.dylib
是绝对目录,其他库/可执行文件调用他时需在 /usr/local/lib/
下找到 libtimelink-tuio.dylib
这个依赖库
libboost_thread.dylib
和 libboost_system.dylib
是相对路径,xxxx.dylib在当前目录调用它;
/usr/lib/libc++.1.dylib
和 /usr/lib/libSystem.B.dylib
是依赖的系统库;
而每个动态库或可执行文件都有个 install_name
的属性,可使用 install_name_tool
命令修改,如下:
install_name_tool -id “@executable_path/../Frameworks/libtimelink-tuio.dylib” libtimelink-tuio.dylib
然后执行 otool -L libtimelink-tuio.dylib
查看修改后的状态:
libtimelink-tuio.dylib:
@executable_path/../Frameworks/libtinyxml.dylib (compatibility version 1.0.0, current version 1.0.0)
libboost_thread.dylib (compatibility version 0.0.0, current version 0.0.0)
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
修改 install_name
之后,重新生成可执行文件,还是出错了,因为 MacApp.app/Contents/Frameworks
默认不存在,需手动创建该目录并拷贝依赖库到该目录下;
再重新生成可执行文件,OK,但是无论是打包或者直接拷贝到测试的电脑,都是原来的错误;
另外还有一个经常出现的 bug,Xcode
中丢失 mainmenu.xib
找不到,把工程文件拷贝一份,在拷贝的那个工程打开再重新编译又OK了。
难道它依赖的其他的库 boost_system boost_thread
的 install_name
有问题?但不管换成相对路径还是绝对路径都不行;
然后想到将 boost
和 tinyxml
以静态库的形式链接到 libtimelink-tuio.dylib
中,减化库与库之间的依赖:
- 重新编译
boost
的libboost_thread
&libboost_system
静态库(因为之前没有编译静态库) - 重新编译
tinyxml
静态库 - 重新编译
libtimelink-tuio
静态库
此时 objective-c
的 MacApp
工程重新链接这个头文件库文件,编译通过了,但链接时出现问题 apple mach-o linker error
我已经看不下去了,当初为啥那么傻 —— 来自2019年的自己
如下是一个很傻B的试验,我不打算整理这一段 -_-!
--> 用xcode建个c++的工程,然后链接xxxx.a静态库(直接将xxxx.a拖到左边目录,就路径等就自动配置了),然后一大坨相同的错误;
--> 使用动态库的时候都能链接成功的,究竟是什么原因呢?
分析了这样的情况,比如有一下目录:
|-- main.cpp
|-- a.cpp inc1.h inc2.h
|-- b.cpp inc2.h inc3.h
用g++编译程序的时候应该是这样的:
gcc -c a.cpp 生成 a.o #编译
gcc -c b.cpp 生成 b.o #编译
gcc -static -o ab.a a.o b.o # 静态库
gcc -o test1 main.cpp ab.a # 链接
gcc -shared -o ab.dylib a.o b.o # 动态库
gcc -o test2 main.cpp -L ./ -lab #链接
使用命令:otool -L ab.a,看到的依赖的库是:a.o b.o,
原来静态库是不做链接对,只是将一个一个的.o集在一起,做成一个.a,
也就是.a是只编译但没有链接的,
难怪编译依赖库的静态库时基本不会出问题,而动态库却经常链接出错,因为静态库不做链接(这就意味着生成可执行文件(调用这个静态库的)时就需要链接了);
所以也不难解释,现在加到项目工程中,编译、生成可执行文件时,链接静态库的时候还是出一大堆的问题;
但是我将所有依赖的库的静态库都加进工程里,还是出现这样的错误,奇怪了;
最后不用 libtimelink-tuio.a
静态库了,重新编译一个 libtimelink-tuio.dylib
(不依赖于boost库)
将 libtimelink-tuio.dylib
的 install_name
改成 /Users/Shared/timelink-tuio/libtimelink-tuio.dylib
libtimelink-tuio.dylib:
/Users/Shared/timelink-tuio/libtimelink-tuio.dylib (compatibility version 1.0.0, current version 1.0.0
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
将 libtimelink-tuio.dylib
放到 /Users/Shared/timelink-tuio/
目录下
将 objective-c
工程的库目录改成 /Users/Shared/timelink-tuio/
,OK
打包,将依赖的动态库放在打包的 Packages 工程的 payload 的 content 列表的 Users-Shared-timelink-tuio 下,然后生成 mpkg 安装包,拿去测试的电脑,测试通过了!!!
注:以上是测试安装包;
总结:对编译原理没完全懂,有些方法还没有试就已经不淡定了;
这个解决方法算是用了旁门左道的,xxxx.app/Contents/Frameworks/这个东西还没解决;
这东西又催的急,感觉快撑不住了!还好算是好了!
有点傻,有很多步骤其实没有必要!可能这就是成长的历练吧! —— 来自2019的自己