anti scroll

ブラウザと小説の新しい関係を模索する

HomebrewからMacPortsへの移行でハマった部分(主にRust周り)

2023年の中旬ごろ、HomebrewがBigSurなどの古いMacOSをサポートから外してしまいました。

しばらくは「なんとかなるさ!」と使っていたのですが、半年もしないうちに重要なパッケージが更新できなくなり…

特に痛かったのは、libheifが更新できなくなって、ImageMagicでavifを扱えなくなったことでした。

そこで古いOSもサポートしていると噂のMacPortsに移行することに。

他の移行先としてnixなども考えましたが、ちょっと調べた感じだと「まだ過渡期なのかな」と思ったので、無難にMacPortsにしました。

で、実際に使ってみたら、拍子抜けするぐらい、普通に移行できました。

しかし、やはり一部ハマったものもあったので、その経験を残しておきます。

ハマりポイントは2つで、自分の場合はcargo-edit(Rust)とfabric(Python3)でした。

cargo-editのインストール(と起動)に失敗する

MacPortsを運用してしばらくして、Rustのcargo-editというcrateのインストールに失敗することに気付きました。

エラーメッセージを見ると、libiconv.dyldという動的ライブラリのリンクに失敗している模様です。

で、どうもそのリンク先が、MacPortsが管理するlibiconvっぽい…

MacPortsでlibiconvをインストールした覚えはないのですが、広く使われてる文字列変換のライブラリなので、まあなにかのついでにインストールされたのでしょう。それがリンクされて、エラーになったみたいです。

エラーになる理由は、MacPortsでインストールされるlibiconvが、世間一般に公開されている「普通の」libiconvとは、ちょっとだけ異なるから。

なんか他のエコシステムのlibiconvと衝突しないように、いくつかの関数が別名で登録されているらしいのですね。

だからこれをリンク先の動的ライブラリとして選択されてしまうと、リンクエラーになってしまうわけです。

なにが異なるのかは、

nm -a /opt/local/lib/libiconv.dylib | grep iconv
nm -a /usr/local/lib/libiconv.dylib | grep iconv

の出力結果を比べたらわかるはずですが、実際にやってみたら「アレ? 別に変わったところはないけど?」という感じでした。

でもまあ、リンクエラーが起きてるんで、なんか違うんでしょう(笑)。

そういうわけで、MacPorts外の世界のプログラムにlibiconvをリンクするときは、MacPortsが使っている(特別仕様の)libiconvをリンクさせないようにする必要があります。

今回トラブったcargo-editについても、DYLD_LIBRARY_PATHが最初に/opt/local/libを探す仕様になっているせいで、そのままコンパイルするとリンクエラーになるわけです。とはいえ、DYLD_LIBRARY_PATHの上書きは、他のトラブルを起こすことが多いので避けたいところです。

これを解決する方法として、自分の環境では次の2つがうまくいきました。

1つ目は、Rust固有の環境変数を使うもの。

幸いなことに、RustにはRUSTFLAGSという環境変数を通じて、コンパイル時のオプションを渡せる仕組みが用意されています。これを使ってリンク先を変更することができました。

.zshrcとかに、

export RUSTFLAGS="-L/usr/local/lib"

を付け足せばOKです。

もちろんBigSurでは/usr/local/libにlibiconvは入っていないので、ソースからコンパイルして、/usr/local/lib/にインストールしました。

./configure --prefix=/usr/local && make && make install

2つ目の方法はもっと簡単で、cargo-editをインストールするときだけMacPortsのlibiconvを無効にする、という方法。

# いったん無効にする
sudo port -f deactivate libiconv
# cargo-editをインストール(システム依存のlibiconvが使われる)
cargo install cargo-edit
# 終わったら再び有効にする
sudo port activate libiconv

こうすると、MacPorts以外のlibiconvにリンクしてくれます。

自前で/usr/local/libなどにインストールしてない状態でもうまくいったので、BigSurのどっかしらに、普通のlibiconvがあるんでしょう(笑)。

これでcargo-editはインストールできました。

ただ自分の環境では、これで終わりではなく、その後にcargo-edit系のコマンド(upgrade, add, rm, set-version)を実行したら、また次のようなエラーが出ました。

~/.cargo/registry/index/github.com-1ecc6299db9ec823 is unusable due to having an invalid HEAD reference: reference 'refs/heads/main' not found; class=Reference (4); code=NotFound (-3)

なんかcargo-editに関するgithubのレポジトリ情報が~/.cargo以下に適切に配置されていない、みたいなエラーです。

最近のcargoは、パッケージを管理するcrates-ioというサーバーとの通信に、sparseというプロトコルを使うようになったらしいのですが、cargo-editをインストールする際にもこのプロトコルが使われたことで、githubのrepositoryが~/.cargo/registry以下に適切に登録されなかったっぽいです。

以前のcargoは、巨大なリポジトリをgitプロトコルでローカルに引っ張ってくる仕組みで、その際レポジトリの構造がローカル環境にも配置されていたのでしょう。

しかしcargoのプロトコルの刷新で、それがなくなったことにより、このエラーが出たのだと思います。

エラーを見る限りcargo-editはローカルにgit-repositoryが配置されてないと動かないらしいので、最初にcargo install cargo-editするときだけは、gitプロトコルcrates-ioと通信するようにします。

これも2つの解決方法があって、1つはCargo.tomlに

[registries.crates-io]
protocol = "git"
#protocol = "sparse"

と書く方法。もちろん終わったら"sparse"側を有効にします。

もう一つは環境変数CARGO_REGISTRIES_CRATES_IO_PROTOCOLをセットする方法で、.zshrcなどに

export CARGO_REGISTRIES_CRATES_IO_PROTOCOL="git"

と書いておきます。

こうした上で、cargo uninstall cargo-editしてから、cargo install cargo-editすると、正常にインストール&起動するようになりました。

MacPorts経由のfabricが動かない

cargo-editほど大変ではありませんでしたが、fabricもすんなりとは動きませんでした。

最初はMacPortsfabricで検索したら、pythonのそれぞれのバージョンごとに用意されていることがわかったので、素直にそれをインストールしました。

しかし実際に使ってみると、いくつかの処理がエラーで動きませんでした。

そこでpython3pip3MacPortsでインストールし、fabricだけpip3でインストールするようにしたら上手くいきました。原因はわかりません(笑)。

ちなみにMacPorts経由でインストールしたpipでインストールするfabコマンドは、/opt/local/Library/Frameworks/Python.framework/Versions/3.xx/bin/にインストールされるので、sudoで実行する必要があります。本当はvenvとか使ったほうが良いんでしょうが、面倒なのでスキップしました。

# python3とpip3をインストール
sudo port install py311 pip-3.11

# pip, pip3ともにpip-3.11を使用
sudo port select --set pip pip-3.11
sudo port select --set pip3 pip-3.11

# Macportsのpipでfabricをインストール(sudoに注意)
sudo pip install fabric