大学时代曾经一度在 Linux 和 Windows 之间挣扎徘徊,直到后来开始用 Mac,几乎是瞬间就觉得各种满意。好用的命令行加上好用的 UI,基本上不能奢求更多了。不过近年来感觉 Mac OS X 好像在某些奇怪的路上越走越远,特别是在命令行的兼容性方面经常出各种各样的事情。比如之前某次由于一个奇怪的原因需要手工恢复一部分 dotfile 配置文件,于是直接用 cp 命令从 Time Machine 的备份里把一堆文件复制过来,结果系统各种 run 不起来,后来发现好像是奇怪的权限问题,总而言之似乎是 OS X 在 shell 的基础权限之外又做了其他的权限,而 cp 不知道这些东西,所以拷贝过来的东西也用不了。由于我也不是 sys admin,对这些东西也不感兴趣,最后就用 Finder 比较麻烦地重新拷贝了一遍才好了。

不过今天要 fix 的是这个叫做 System Integrity Protection (SIP) 的东西,又叫 rootless,总之就是保护系统了。听上去感觉很有用的样子,似乎确实也很有用,不过刚出来的时候好像导致 homebrew 出了很多问题,然后最近由于 DYLD_LIBRARY_PATH 的问题终于忍无可忍决定要把它 disable 掉。

对 Linux 编程熟悉的同学应该都知道 LD_LIBRARY_PATH,就是可以设置一些搜寻动态链接库的路径,通常安装一些第三方的库,如果不是直接安装到系统的 /usr/lib 之类的路径下面去(比如没有 root 权限,或者不想污染系统)的话,就可以把任意的路径加到 LD_LIBRARY_PATH 里去,让其他的程序还是可以找得到这个第三方库的 shared library。而 DYLD_LIBRARY_PATH 就是 OS X 的 LD_LIBRARY_PATH 对应物(好像直接用 LD_LIBRARY_PATH 也可以)。

然后现在 SIP 为了“安全起见”,把 LD_LIBRARY_PATH 和所有 DYLD_ 开头的环境变量全部禁用了。症状就是一个程序在启动一个子进程的时候,是会继承父进程的环境变量的,但是环境变量里的这几个项会被系统给屏蔽掉。我也不知道为什么这个会破坏系统安全,但是确实这样之后带来各种各样的麻烦,比如在 iPython 里要是用到 CUDA 的库之类的,就会找不到 shared library。如果想用 lldb 去调试一个依赖于一些第三方动态库的程序,或者用 Makefile 来启动一些 tests,也会发现找不到这些动态链接库。之前找到一个临时的解决办法是先用 otool -L 来列出你编译出来的程序依赖于哪些未 resolve 的动态链接库,比如这样的:

your-program-file
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
    @rpath/libcudart.7.5.dylib (compatibility version 0.0.0, current version 7.5.20)
    @rpath/libcublas.7.5.dylib (compatibility version 0.0.0, current version 7.5.20)
    @rpath/libcurand.7.5.dylib (compatibility version 0.0.0, current version 7.5.20)

这些 @rpath 就是未 resolve 的,然后用 install_name_tool 把这些 @rpath 换成你知道的绝对路径,比如:

install_name_tool -change @rpath/libcudart.7.5.dylib \
    /usr/local/cuda/lib/libcudart.7.5.dylib your-program-file

当然每次重新编译过之后都又得 fix 一遍。非常麻烦,后来我发现可以直接把 SIP disable 掉,方法如下:

  1. 重启系统,按住 Command+R,在出现的界面里选 Utilities > Terminal
  2. 在出现的终端里输入 csrutil disable
  3. 正常重启系统。

然后就一了百了了!不过没有了 SIP,也许系统不够安全了呢?不过要是系统真的不够安全还有办法就是换系统!特别是现在 Windows 都开始直接支持运行 Linux 的 binary 了,说不定几年之内“码农友好”的操作系统的局面会逐渐开阔起来呢!拭目以待咯。