mise + linuxbrew 環境で cargo install したバイナリが VSCode に認識されない問題
TL;DR —
miseで Rust を管理している環境では.cargo/envが no-op になる。.profileでexport PATH="$HOME/.cargo/bin:$PATH"と無条件に書くのが確実。
前の記事の RTK のバグ報告のために深夜にせこせこやってたんですよ。
で、cargo install --path . してローカルのバイナリで確認しようとしたら、Claude Code が旧バイナリを使い続ける。小一時間ハマってイライラしたので記録しておく。
症状
cargo install --path . # ローカル fix 済みバイナリをインストール
which rtk # → /home/linuxbrew/.linuxbrew/bin/rtk ← 旧バイナリ
~/.cargo/bin/rtk のはずが、linuxbrew の rtk が勝っている。
なにやっても変わらねぇ…
調査
PATH の順序
1 ~/.local/share/mise/shims
2 /home/linuxbrew/.linuxbrew/bin ← ここで rtk を拾う
...
7 ~/.cargo/bin
linuxbrew が .cargo/bin より前にいるんでよくある単純な PATH 順の問題だろうと甘く見てました。はい。
そこからはまりまくった。
.bashrc に追記しても効かない
Claude さんのおすすめにより、.bashrc 末尾に . "$HOME/.cargo/env" を追記して VSCode を再起動、結果変わらず。そりゃそうだろ。前調べた時って非インタラクティブじゃなかったっけ?
改めてどういうシェルで動いているか確認した。
echo $-
# → hmtBc ← i がない = 非インタラクティブ
ps -p $$ -o args=
# → /bin/bash -c source ~/.claude/shell-snapshots/snapshot-bash-XXX.sh
ですよねー。
Claude Code は非インタラクティブ bash でコマンドを実行している。.bashrc の先頭には標準の非インタラクティブガードがあるので、追記した内容に到達する前に return してしまう。
case $- in
*i*) ;;
*) return;; # ← ここで終わり
esac
Claude Code はシェルスナップショットを使う
/proc/$PPID/environ で VSCode プロセスの PATH を確認すると、Claude Code の PATH と同じ構造だった。Claude Code は VSCode プロセスが持つ環境変数をスナップショットとして保存し、それを各コマンド実行時に source している。
つまり VSCode プロセス自体の PATH を直さないといけない。
.profile に追記しても .cargo/env が no-op になる
さっきの .bashrc への追記だと駄目なことは分かったので、.profile 末尾の eval "$(mise activate bash --shims)" の後に . "$HOME/.cargo/env" を追記して再起動した。が、変わらず…
なんでだよ、と思いつつ.cargo/env を見てみたら中はこうなってた。
case ":${PATH}:" in
*:"$HOME/.cargo/bin":*)
;; # すでにある → 何もしない ← ここに入る
*)
export PATH="$HOME/.cargo/bin:$PATH"
;;
esac
抜けてるじゃねーか!最初に中身を確認しろよ!とセルフ突っ込み。
mise activate bash --shims が Rust(mise 管理)のパスとして ~/.cargo/bin をすでに PATH に追加している。.cargo/env はそれを検知して順序を変えずにスキップする。linuxbrew より後ろの位置に居座ったまま。
VSCode の環境取得
Claude さんに順序立てて調べてもらったところ以下の回答でした。
VSCode は起動時に
bash --login(非インタラクティブ)を使って環境変数を取得する。.profileは実行されるが、.profileが.bashrcを source しようとしても非インタラクティブガードで早期 return する。mise activate --shimsだけが効いてmise/shimsが先頭に入るが、.cargo/envは no-op で linuxbrew より後ろに.cargo/binが残る。
だめじゃん。
解決策
ということで、.profile にパスを直接書く。
# ~/.profile(mise activate bash --shims の後)
# .cargo/env は mise が .cargo/bin を追加済みの場合スキップするので無条件で prepend する
export PATH="$HOME/.cargo/bin:$PATH"
PATH に重複エントリが生まれるが無害。確認。
# VSCode を完全終了してから、修正済みの .profile を持つシェルで起動
ps aux | grep code # プロセスがないことを確認
code .
# Claude Code 内
which rtk # → ~/.cargo/bin/rtk ✅
まとめ
| 試したこと | 結果 | 理由 |
|---|---|---|
.bashrc に .cargo/env 追記 | ✗ | 非インタラクティブ bash、早期 return で効かない |
.profile に .cargo/env 追記 | ✗ | mise が先に .cargo/bin を追加済みで no-op になる |
.profile に export PATH=... 直接記載 | ✅ | 常に先頭に prepend される |
こういうパスの解決問題、自分はよくはまるんだけどみんなどうやってるんだろうか。
エレガントな解決方法でも探してみるかぁ。
→ これ書いた後に Claude さんに相談してみたら、environment.d で管理する方法もあるとのこと。でもこれ一番最初に読まれて結局後勝ちになるので、.profile, .bashrc の2つで管理した方がいいとの結論に至った。