homebrew — Mac OS X 下新的软件包管理工具

虽然 Mac OS X 自带了不少 Unix 下的开源软件,比如 vim, ruby, python, perl 等等,也自带了许多常用的库,包括 iconv, zlib 等等,但我们仍然有时会需要自己动手安装一些这样的软件或者库,要自动化这样的安装,现有最常见的选择是 MacPortsFink,其中 MacPorts 是基于源代码的包管理,并不在自己的库里储存软件的实际内容,只有一个定义如何编译代码的 Portfile 和一些专门针对这个平台的 patch;而 Fink 则是 Apt 包管理系统在 Mac OS X 下的一个克隆,采用二进制分发,用户直接从 Fink 的仓库中下载安装软件。

这两种方式各自有各自的优点和缺陷:

MacPorts 基于源代码的管理优点是非常灵活,更新很快 (很多时候更新只需要修改一下 Portfile 里的版本号和压缩包校验码就可以),用户要订制安装也可以简单的通过修改 Portfile 实现,而且很多开源软件的安装配置会有多种模式 (典型的大都通过 configure 步骤配置),在 MacPorts 中可以方便地通过 variants 参数指定,而不必像二进制分发那样,在远程服务器上编译的时候就定死了。而 MacPorts 的问题是,它希望自己安装的每套软件,所有的依赖都在它自己这个系统内 (一般就是你的 /opt/local) 解决,就算 Mac OS X 系统原生自带了满足依赖的库,它也坚决不用,这样就给你的系统增加了许多冗余,也客观增加了管理上的难度,典型的情况是:你的系统里装了两套 Python,该怎么管理外部安装的 Python 模块?比如通过 easy_installsetup.py 安装的,往往很难记住到底装到哪里了。

而 Fink 虽然不会这么自作主张地添加依赖,最大的问题是更新不够及时,这也是缺乏维护人手导致的。二进制安装的缺点在上面也提到了:不便定制。

所以 Homebrew 的出现,也许不是很及时,但在现在仍然是很必要的,它有这么一些优点:

  1. 尽可能的利用你的系统里自带的库,包括 zlib, OpenSSL, Python 等等,只要 Mac OS X 自带了,它就不会另装一份。

  2. 定制简单,通过用 Ruby 写的 Homebrew formula 来定制,甚至可以灵活的跟踪直接来自版本管理库的最新软件

  3. 用 Git 管理和同步自身

  4. 直接装在 /usr/local 下,这样可以少定义很多各种 PATH 环境变量

其中第一点尤为重要。好的,下面简单介绍一下 Homebrew 的安装,以及它是如何工作的。

安装

首先,Homebrew 的原则是“No sudo”,也就是说,既然 Mac OS X (client 版本) 绝大部分情况下都是归你这个有管理员权限的用户,为什么在自己的 /usr/local 下安装程序还需要 sudo 呢?所以,首先:

sudo chown -R `whoami` /usr/local

然后可以正式开始安装,我推荐的安装方式是先用 git-osx-installer 装上 git,然后用 git 安装:

cd /usr/local
git init
git remote add origin git://github.com/mxcl/homebrew.git
git pull origin master

这么做的实际作用是把你的 /usr/local 目录变成了一个本地 git 仓库,只不过这个仓库只跟踪跟 Homebrew 相关的更新,并不影响任何其他软件的安装。

这样安装会在 /usr/local 下创建 Library 这个目录,然后在 /usr/local/bin 中加入 brew 这个 ruby 脚本。

使用

安装完毕,下面就可以试试了:

brew search

这个命令用来搜索所有可以通过 homebrew 安装的软件,不带任何参数的时候就是列出所有的。可以看到数量已经不少了。

下面就是选择安装,比如我想安装 unrar:

$ brew search rar
gnu-scientific-library     unrar

$ brew install unrar
Warning: It appears you have Macports or Fink installed
Although, unlikely, this can break builds or cause obscure runtime issues.
If you experience problems try uninstalling these tools.
/usr/local/Library/Formula/unrar.rb:3: warning: already initialized constant ALL_CPP
==> Downloading http://www.rarlab.com/rar/unrarsrc-3.9.4.tar.gz
######################################################################## 100.0%
==> g++ -O4 -march=core2 -mmmx -msse3 -w -pipe -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE all.cpp -o unrar
/usr/local/Cellar/unrar/3.9.4: 3 files, 320K, built in 13 seconds

可以看到,unrar 被安装到了 /usr/local/Cellar/unrar/3.9.4 这个目录下,但这样我们访问起来显然很不方便,所以 Homebrew 会在 /usr/local/bin 下面创建到 unrar 程序的符号链接,如果安装的是库之类的,也会对应在 /usr/local/lib 这样的目录下创建符号链接。所以这是一套类似 GoboLinux 的软件管理方式。

安装后就可以用 list 命令列出:

$ brew list
pkg-config  unrar

更新

如果用了一段时间,需要更新同步上游的 Formula,可以简单地:

$ brew update
From git://github.com/mxcl/homebrew
 * branch            master     -> FETCH_HEAD
Updated Homebrew from 60600885 to 60600885.
No formulae were updated.

Homebrew 会通过 git 完成同步。

总结起来,Homebrew 是一套很有新意的软件包管理工具,虽然它的更新及时程度还有待考验,但至少在目前还是比较令我满意的解决方案。

Mac 下使用常见主机

手头在玩的几个主机和掌机包括 Wii, PS2, Xbox 360, PSP 和 NDSL,大部分网上能找到的信息都是 PC 上的使用方法,Mac 下要用的话,偶尔有点地方需要注意的,这里顺便记录一下。

Wii 现在大家一般都软解后用 USB Loader,这个一般无非是把下载下来的游戏镜像文件复制到移动硬盘里的 WBFS 文件系统中,在 Mac 下,WBFS for MacOS X 是最方便的工具。偶尔需要提取 Wii 游戏光盘镜像时,wiiscrubber-ng 是个不太完全的移植,我略作了一点修改。

PS2 无非是刻盘,这个用系统自带的 Disk Utility 就可以胜任。

Xbox 360 的刻盘稍微无法一点,因为是双层 DVD,有时需要设置分层点,iBurn360 或者 OSx360 都可以设置分层点进行刻录,其中 OSx360 在刻录新的 Wave 3 游戏时,需要去掉“Require Stealth Verification”选项。

PSP 偶尔需要转换 CSO 和 ISO 格式,Prometeus 是一个很好的工具。

NDSL 没什么可说的,使用了烧录卡后就是往 TF 卡里复制游戏而已。

在 Mac 下解决 Wii Sports Resort 不能启动的经历

  1. 收到从淘宝购买的 Wii MotionPlus
  2. WBFS for MacOS XWii Sports Resort 美版 ISO 复制到移动硬盘
  3. 打开 Wii,用 USB Loader GX 启动 Wii Sports Resort,蓝屏,Error #002 错误
  4. 启用 USB Loader GX 的“防 002 错误”功能,再次启动 Wii Sports Resort,黑屏重启
  5. 发现需要从 Wii Sports Resort 的光盘镜像里提取一个文件放到 SD 卡根目录,但网上没人提供美版的对应文件 (只有日版和欧版的)
  6. 发现用来提取文件的 WiiScrubber 只有 Win32 版本
  7. 找到 WiiScrubber-ng,一个 Unix 移植
  8. 下载编译 WiiScrubber-ng 的源代码,发现缺少 key.bin 文件无法执行
  9. 下载 MakeKeyBin 的源代码,提取出跨平台部分单独编译,生成 key.bin
  10. 运行 wiiscrubber-ng,发现提取文件部分并没有移植
  11. 少量修改 wiiscrubber-ng, 加入提取文件功能,获得所需的 player.dol 文件
  12. 复制获得的文件到 SD 卡中,启用 USB Loader GX 的“Alternate DOL”功能,成功进入 Wii Sports Resort, 看完 MotionPlus 的使用演示
  13. 退出游戏,关闭“Alternate DOL”功能,再次启动 Wii Sports Resort,正式开始游戏

dump 混合光盘镜像中的 ISO 9660 分区

Leopard / Snow Leopard 光盘镜像是混合 (hybrid) 分区格式,也就是一个磁盘镜像中,既有 HFS+ 分区,也有 ISO 9660 分区 (Boot Camp 驱动就存放在这个分区上),在 Mac OS X 上只会挂载前者,在 Windows 下只会挂载后者。虽然可以在 Terminal 下手工挂载后者,但也不是很方便,这里记录一个脚本,方便直接把 ISO 9660 分区 dump 为 ISO 文件:

$ cat dump.sh
#!/usr/bin/env bash
DISK=`hdiutil attach -noverify $1 | awk '/Apple_partition_scheme/ { print $1 }'`
dd if=$DISK of=$2 bs=512 count=`hdiutil pmap $DISK | awk '/WINDOWSSUPPORT/ { print $6 }'`
hdiutil detach $DISK

使用方法:

$ ./dump.sh snowleopard_10a354_userdvd.dmg bc.iso

Packaging for Installation on Mac OS X

在 Mac OS X 下为程序打包该用什么格式?这是个很有趣的问题,首先,显然绝大部分的应用程序都应该:

  • 使用手动安装,也就是一个独立的 .app,里面通过 @executable_path/../Frameworks/ 的方式链接所有依赖的第三方库,也就是说,不往系统相关目录里乱放东西。这是 Apple 官方的 Software Delivery Guide 中推荐的安装方式
  • 支持用 Sparkle 这样的自动更新框架,实际上符合上一点的也就自然可以用 Sparkle 完全自动的完成更新。
  • .zip 格式分发。为什么不用 .dmg?因为 .dmg 不容易直接解压,挂载速度比 .zip 慢得多,增加拖动的手续,所以我支持这篇 zip vs dmg 的观点。

SunPinyin 安装界面

但是如果遇到特殊的情况呢?比如你写的是一个非得往系统目录 (/Library/...) 安装内容的软件呢?比如我最近参与改进的 SunPinyin 输入法,就必须打包为 Installer 支持的 .pkg 格式安装了,否则很难确保软件被正确的安装。

关于这个打包方式,最重要的一点心得是:千万不要用 Apple 自己提供的 PackageMaker,这恐怕是 Apple 开发的最恐怖的一个开发辅助工具了,因为:

  • 它必须用图形界面修改内容
  • 它保存的 .pmdoc 格式非常混乱,而且居然喜欢把绝对路径存入文件中
  • 不支持 Installer Plugins 扩展

那替代的工具是什么呢?是一个非常棒的第三方工具: Iceberg,它能:

  • 打包出 Mac OS X 10.2+ 以上都支持的 .pkg bundle 格式
  • 界面比 PackageMaker 友好得多,而且有非常详尽的文档,也很方便调试
  • 支持 Installer Plugin

涉及打包、Sparkle 的 appcast 自动生成,Iceberg 的使用等问题,都可以参考 SunPinyin 目前使用的代码