上禮拜主要工作的桌機突然掛掉,經過一番交叉測試,應該是主機板掛了,還好還有筆電,接上大螢幕還可以繼續工作,程式專案的部分有遠端 Git 庫存不怕掉檔案,但其他一些文件、相片就要想辦法讀出來了,macOS 讀 Windows 的 exFAT、NTFS 沒問題,反倒是不支援 ext4,這點令人感到意外,調查一波後發現,macOS 要掛上 ext4 並不簡單,要抉擇用哪些工具鏈,還要自行編譯,自己曲曲折折走對一條路後寫下這篇筆記。

macOS 原生不支援 ext4,當插入 ext4 硬碟,系統可以認得有硬碟插入,在磁碟工具程式可以看見它以及分配的設備編號(例如 disk4s1),但無法掛載,我們需要利用 FUSE 機制來掛載它。

在 macOS 世界,FUSE 底層套件有兩個選擇,傳統的 macFUSE(= OSXFUSE = Fuse4X)使用 macOS 核心擴充機制(KEXT),KEXT 已經逐漸被淘汰,所以我選用無 KEXT 成分的 FUSE-T,FUSE-T 是以 NFS 的方式掛載,讓 ext4 或其他檔案系統變成一個假的網路硬碟。

要把整套工具搭起來需要:

  • Xcode command line tools,內含 Git、make 等開發工具。
  • Homebrew,macOS 世界的套件管理器。
  • FUSE-T,FUSE 底層套件。
  • pkg-config,編譯 ext4fuse 所需工具。
  • ext4fuse,掛載 ext4 硬碟工具。

Xcode command line tools

一行安裝:

$ xcode-select --install

裝完就有 Git 和 make 可用了。

Homebrew

Homebrew 是 macOS 世界的套件管理器,它也可以在 Linux 工作,只不過沒什麼人用罷了,Linux 早有 APT 等主流套件管理器了,Homebrew 安裝請參見它的文件。

FUSE-T

有了 Homebrew,安裝 FUSE-T 就很簡單了:

$ brew install macos-fuse-t/homebrew-cask/fuse-t

裝完它會在 /usr/local/lib/ 內,另外 /usr/local/lib/pkgconfig/fuse-t.pc 為 FUSE-T 的 pkg-config 配置檔,內容如下:

prefix=/usr/local
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include/fuse

Name: fuse-t
Description: Userspace FUSE implementation for macOS
Version: 1.0.44
Libs:  -L${libdir} -Wl,-rpath,${libdir} -lfuse-t
Cflags: -I${includedir}

不論是 macFUSE 或 FUSE-T,他們都是 FUSE 機制的底層套件,具體要掛載 ext4 或其他檔案系統,還要另外安裝各自套件,後續我們需要 ext4fuse,並且還需要自行編譯。

編譯 ext4fuse 需要引用 FUSE-T 的 fuse.h,根據上面的定義,fuse.h 應該位在 includedir 變數位置,也就是 /usr/local/include/fuse/ 內,而 fuse.h 及其他源碼在專案 libfuse 內,我們把它 clone 下來:

$ git clone https://github.com/macos-fuse-t/libfuse

然後把 libfuse/include/ 所有檔案複製到 /usr/local/include/fuse/ 內:

$ sudo mkdir /usr/local/include
$ sudo mkdir /usr/local/include/fuse
$ sudo cp -R ~/Projects/libfuse/include/* /usr/local/include/fuse/

至此前置備料完成一半,另一半是裝 pkg-config。

pkg-config

pkg-config 是編譯期間的相依套件管理工具,前面我們已經備好 FUSE-T 的 pkg-config 配置以及源碼,但還需要安裝 pkg-config 工具本身,為了避免落入編譯輪迴地獄,這裡我們用速成方式一行搞定:

$ brew install pkgconf

pkgconf 是與 pkg-confg 相同,重新發明的輪子,具體差異為何不深究,總之安裝很間單。

至此備料完畢,總算可以編譯了。

ext4fuse

ext4fuse 是掛載 ext4 硬碟工具,注意它只能讀不能寫。

ext4fuse 編譯時需要引用 fuse.h,而因為我們用的是 FUSE-T,因此這 fuse.h 也必須是 FUSE-T 的 fuse.h,這句話出現了六次「fuse」,看來頗令人困惑,總之就是 ext4fuse 也要選用 FUSE-T 的修改版,首先把它 clone 下來,注意網址中間是「macos-fues-t」:

$ git clone https://github.com/macos-fuse-t/ext4fuse

然後跑 make:

$ make

下面出現一陣幾哩呱啦,警告什麼的,先無視,編譯完,專案資料夾內應該會出現一支執行檔 ext4fuse,終於我們可以掛上 ext4 了:

$ mkdir ~/ext4_mount
$ sudo ./ext4fuse /dev/disk4s1 ~/ext4_mount -o allow_other

此時在 Finder 應該就可以看到掛上去的 ext4 了,賀 🎉。

用完卸載:

$ sudo umount ~/ext4_mount

如果卸載失敗,就先關電腦,再拔 ext4 硬碟,這樣比較安全。