MacOS运行Gamit track模块时出现dyld libSystem.B.dylib Library not loaded错误

问题描述

在使用MacOS版本的Gamit软件的track模块时,会出现类似错误:

1
2
dyld[xxxx]: dyld cache '(null)' not loaded: syscall to map cache into shared region failed
dyld[xxxx]: Library not loaded: /usr/lib/libSystem.B.dylib

导致track模块无法正常运行。官方文档仅说明是由于Apple Silicon内存限制所造成的,并未给出具体原因及解决方法。

原因探究

通过查询Apple的帮助文档,结合一位Apple DTS工程师的说法,这背后其实有着悠久的历史(?

早在 Mac OS X 发布之初,Apple还不支持 SDK。当安装开发者工具时,它会在当前系统的绝对位置放置头文件,例如, 头文件将放置在 /usr/include/pcap/pcap.h,工具会在这些绝对位置查找头文件。同样的情况也会发生在库中,只不过链接器会在 /usr/lib 中查找。到目前为止,Unix系统仍然遵循这套规则。

但是这种方法在Apple工程师看来是“无稽之谈”,因为随着Apple设备向跨平台的方向发展,在macOS 上发布iOS库毫无意义,因为它只是一堆无法执行的代码。所以,Apple使用了一种 dynamic linker shared cache 共享缓存技术来取代dylib库。这本意是好的,但是,当Mac转向Apple Silicon后,问题就出现了。

由于磁盘中的标准库,例如本文中的libSystem.B.dylib被存放在了共享缓存中,每次执行需要该库的可执行程序,该缓存都会被加载到一个固定的内存地址范围中,然后在运行可执行文件时由dyld链接。但是,如果你的可执行文件太大,以至于扩展到了共享缓存的地址范围,共享缓存自然就会报错无法执行了。在英特尔 Mac 上不会出现这个问题,因为在英特尔Mac上,这个固定的地址要大得多。

不巧的是,Gamit的老旧代码在今天看来存在诸多问题,其track模块中定义了一个巨大的静态数组,大小远远超过了Mac共享缓存机制的最大内存限制(1.993 GB)。所以,调用track时,内存中的共享缓存被其覆盖,动态链接库libSystem.B.dylib自然也就找不到了。

解决方案

很显然,从根源上解决该问题的方式是避免使用如此庞大的静态数组,利用MALLOCALLOCATE动态分配内存空间——但这对于我们普通用户来说是不现实的。

参考课程老师的意见,选择修改“~/gg/opt/gamit10.71/kf/track/track_com.h”头文件中最大测站数和最大历元数:

在文件约47行,将几个数组的定义修改为:

1
2
3
4
5
6
parameter ( max_site =  5 )
parameter ( max_kine = 4 )
parameter ( max_prn = 100 )
* MOD TAH Increased max_chan for GNSS solutions.
parameter ( max_chan = 40 )
parameter ( max_epochs = 18000 ) ! 12-hr flight with 2Hz data

也可以修改为其他值,只要小于1.993 GB即可。

然后删除“~/gg/opt/gamit10.71/kf/track“目录下的可执行程序“track”和库文件“track_lib.a”,重新在该目录终端中执行sudo make进行编译。编译结束后即可即可正常使用track模块。

p.s. 虽然原理不同,但该解决方案也可以解决ubuntu系统中因内存不足引起的“段错误”问题。

参考文献

[1] My libSystem.B.dylib is Missing from my Mac|Apple developer forums

[2] A DTS Engineer‘s Answer from Apple|Apple developer forums

[3] Possible compiler/dyld bug|Apple developer forums

[4] GAMIT/GLOBK Known Issues