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即可。