cargo: command not found, obwohl rustup installiert ist
Symptom: rustup funktioniert, rustup show listet eine installierte und aktive Toolchain auf, aber cargo, rustc und rustfmt schlagen alle mit “command not found” fehl.
Ursache
Unter macOS mit Homebrew ist rustup eine keg-only-Formula. Homebrew verlinkt nur das rustup-Binary selbst nach /opt/homebrew/bin. Die Proxy-Shims, die rustup normalerweise daneben mitliefert, cargo, rustc, rustfmt, cargo-clippy und so weiter, verlinkt Homebrew nicht. Die liegen im Keg:
/opt/homebrew/opt/rustup/bin/
Dieses Verzeichnis wird von Homebrew nie zu PATH hinzugefügt. Also lässt sich rustup auflösen, aber jeder Befehl, den es normalerweise an die aktive Toolchain weiterreichen würde, nicht.
Du kannst das so bestätigen:
$ which rustup
/opt/homebrew/bin/rustup
$ which cargo
cargo not found
$ brew info rustup
==> Caveats
To use rustup, ensure you have "$(brew --prefix rustup)/bin" in your $PATH
Die Toolchain selbst ist in Ordnung, ~/.rustup/toolchains/<target>/bin/ enthält echte cargo- und rustc-Binaries. Die Shims im Keg sind das, was normalerweise davor sitzt und die aktive Toolchain auswählt; ohne sie auf PATH ist von dieser Maschinerie nichts erreichbar.
Lösung
Füge /opt/homebrew/opt/rustup/bin zu PATH hinzu. opt/rustup ist ein stabiler Symlink, den Homebrew auf die aktuelle Cellar-Version pflegt, er überlebt also Upgrades.
Für ein einfaches Shell-Profil:
export PATH="/opt/homebrew/opt/rustup/bin:$PATH"
Für eine mit chezmoi verwaltete fish-Konfiguration passt das ins selbe Muster wie jedes andere PATH-Fragment pro Toolchain (ein go.fish.tmpl, dotnet.fish.tmpl usw.):
if test -d /opt/homebrew/opt/rustup/bin
path_insert /opt/homebrew/opt/rustup/bin
end
Eine Tücke beim Testen der Lösung
Wenn du bereits eine interaktive Shell offen hast, kann das Sourcen der Lösung in einer verschachtelten Shell wie ein No-op aussehen, obwohl es in einem frischen Terminal einwandfrei funktioniert. In diesem Setup cacht fishs Konfiguration über eine PATHS-Umgebungsvariable, die am Ende von config.fish gesetzt wird, ob die PATH-Einfügung schon gelaufen ist. Diese Variable wird exportiert, sie leakt also in jeden Kindprozess, einschließlich eines verschachtelten fish -c-Aufrufs, mit dem die Lösung getestet wird. Die Einfügelogik sieht PATHS als bereits gesetzt und überspringt sich selbst.
Das ist kein Fehler in der Lösung. Es ist ein Nebeneffekt davon, eine Shell-Startup-Änderung aus einer Shell heraus zu testen, die den Startup schon einmal durchlaufen hat. Zum Verifizieren muss diese Variable für den Testaufruf geleert werden:
env -u PATHS fish -c 'cargo --version'
Ein wirklich neues Terminalfenster hat dieses Problem nicht, da es das veraltete PATHS=true nie geerbt hat.
Fazit
Wenn ein von Homebrew installiertes CLI-Tool “funktioniert”, die Befehle, die es bereitstellen soll, aber nicht, prüfe zuerst, ob die Formula keg-only ist. brew info <formula> gibt den genauen PATH-Hinweis aus, kein Raten nötig.