macOS で pio pkg install が pyexpat の symbol not found で落ちる
初出: 2026-05-19環境: macOS Tahoe (26.x) / Apple Silicon / Homebrew python@3.14 / PlatformIO 6.1.19
症状
pio pkg install や pio run を初回実行すると以下のように落ちる:
ImportError: dlopen(.../pyexpat.cpython-314-darwin.so, 0x0002):
Symbol not found: _XML_SetAllocTrackerActivationThreshold
Referenced from: .../pyexpat.cpython-314-darwin.so
Expected in: /usr/lib/libexpat.1.dylib
Command '[...python', '-m', 'pip', 'install', ...]' returned non-zero exit status 1.ライブラリのインストールが途中で止まり、firmware がビルドできなくなる。
原因(噛み砕き)
- Python の XML を読む内部モジュール
pyexpatは、libexpatという C のライブラリを動的にロードして使う - Homebrew でビルドされた
python@3.14のpyexpatは、ビルド時に Homebrew の expat 2.7.x 以上が前提 でコンパイルされていて、新しい関数XML_SetAllocTrackerActivationThresholdを呼ぶようになっている - ところが macOS Tahoe (26.x) に最初から入っている
/usr/lib/libexpat.1.dylibはバージョン表記こそ新しいが、Apple の出荷バイナリではこの関数が公開されていない - macOS の動的リンカ(dyld)は、System Integrity Protection の関係で
/usr/lib/配下を優先することがあり、Homebrew 版の expat を使ってくれない - 結果: 起動時に「シンボルが見つかりません」で死ぬ
要するに 「Python が呼びたい関数」と「macOS の標準ライブラリが用意してる関数」がズレてる という状態。
対処(即効)
Homebrew 側の expat を優先させる環境変数 DYLD_LIBRARY_PATH を付ける:
bash
export DYLD_LIBRARY_PATH=/opt/homebrew/opt/expat/lib
pio pkg install毎回打つのが面倒なので ~/.zshrc に書いてしまうのが楽:
bash
# ~/.zshrc
export DYLD_LIBRARY_PATH=/opt/homebrew/opt/expat/lib⚠️
DYLD_LIBRARY_PATHを広く設定すると 他の Mac アプリの挙動も変える ことがある。 副作用を避けたいなら、firmware ビルド時だけ付ける Makefile を作るか、direnv でfirmware/限定にする。
対処(恒久案・優先度低)
- 案A: PlatformIO を
pipxで別バージョンの Python に入れる - 案B: Homebrew が
python@3.14を再ビルドして問題を直すのを待つ - 案C:
firmware/Makefileを作って自動で環境変数を付ける
現状は案Cが現実的:
makefile
# firmware/Makefile (案)
export DYLD_LIBRARY_PATH := /opt/homebrew/opt/expat/lib
build:
pio run
upload:
pio run -t upload
monitor:
pio device monitorなぜ気づきにくいか
- エラーが PlatformIO の中の中(pip → distlib → xmlrpc → pyexpat)で出るので、表面のエラーメッセージは PlatformIO 由来に見える
MissingPackageManifestErrorという別のメッセージが後で出るので、本当の原因(expat)が埋もれがち- ログを上にスクロールして
Symbol not foundを見つけるのがコツ
参考リンク
- Homebrew python@3.14 issue tracker
man dyldのDYLD_LIBRARY_PATHの項