1. 现象
VCMI编译之后可以使用cpack
命令(cmake的一个功能)打包成dmg文件,以便于分发。打包过程中会把需要的依赖文件都打包到最后的.app
文件中,这样就可以保证在其他机器上也可以正常运行编译后的VCMI。
按照之前的文档,编译之后直接执行没有问题,但是使用cpack
打包之后运行缺会异常退出。经过观察基本上发生在第一次战斗中,玩家操作完毕,电脑AI获得控制权的时候就会崩溃退出。
2. 分析
最初怀疑是新版本代码有问题,所以切换到之前版本的代码编译,发现还是有同样的问题。后来经过分析退出的时间点,怀疑是vcmi
的AI代码有问题,因为对代码部分不是很熟悉,所以很长时间没有进展。
后来经过查看cpack
的工作原理,怀疑是AI库对应的依赖文件没有正确打包导致的。
使用otool -L
分析动态库依赖,发现AI目录下的文件没有进行依赖库的处理。还是指向/usr/local/...
下面的dylib文件。而vcmiclient/vcmiserver
已经进行了处理。因此怀疑是因为引入了两份动态库导致的问题,vcmiclient
已经加载了一份动态库,但是当执行到AI库的时候又要从其他位置加载另一份同名的动态库,可能是因为这个原因导致了崩溃。
3. 解决办法
经过查阅cpack
的文档,cpack
打包的时候使用fixup_bundle对依赖库进行处理。因此改造一下打包脚本,脚本文件是osx/CMakeLists.txt
:
1 install(CODE "
2 set(BU_CHMOD_BUNDLE_ITEMS ON)
3 include(BundleUtilities)
4 # 原先的配置文件内容
5 # fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_DIR}\" \"\" \"\")
6 # 修改成如下的内容。注意:以上这三行不要复制到最后的文件中,只复制下面一行即可。
7 fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_DIR}\" \"libVCAI.dylib;libStupidAI.dylib;libBattleAI.dylib;libEmptyAI.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${BIN_DIR}/AI\")
8 " COMPONENT Runtime)
说明:
- fixup_bundle的用法是:
fixup_bundle(<app> <libs> <dirs>)
,通常指定.app
文件路径即可,会自动修复其中的Contents/MacOS
路径下的可执行文件。但是因为vcmi的AI库文件在单独的一个目录中(Contents/MacOS/AI
),所以默认没有办法对AI文件进行处理; - 修改办法是将AI相关动态库作为lib文件添加到
libs
参数中,然后使用dirs
指定库文件所在的目录; - libs 增加
libVCAI.dylib;libStupidAI.dylib;libBattleAI.dylib;libEmptyAI.dylib
这四个AI的文件。使用分割符;
(分号)进行分隔; - dirs 增加这四个文件所在的目录;
- 重新cpack即可。