アプリインストール(rust→librsvg→graphviz→plantuml) - M1 MacBook Air インストール覚書(21)

はじめに

とりあえず必要なものを順番にインストールしていますが、plantuml をインストールしようとして、依存関係の librsvg のインストールでハマりました。librsvg の build で rust を使っているためです。

rust は現状で brew ではインストールできませんが、1.49-beta は Apple Sillicon 対応になっています。Ruby の rbenv と同様に、Rust も Cargo でフォルダごとに管理したいので、1.49-beta を個人でインストールすることにしました。

Rustup でのインストール

Rust のインストールは rustup.rs を対話的に実施するのが通常です。 今回は、beta を支持する必要がありますが、bootstrap.sh から非対話でインストールしたいため、少し工夫します。 調べてみると、rustup を非対話的環境でインストールする方法 - Qiitaという記事を見つけました。通常、

curl https://sh.rustup.rs -sSf | sh

とするところですが、rustup.rs に引数を与えたいため、以下のように sh の引数を設定します。-s -- の後ろの部分が rustup.rs への引数になるそうです。

curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain beta -y

ということで、冪等性を考えて以下のようなスクリプトを .bootstrap.sh に追加しました。ここまでやって、./bootstrap.sh で rust-1.49-beta が $HOME/.cargo/bin にインストールされました。試しに PATH に ~/.cargo/bin にパスを通すと rustc が動作しました。

# Install Rust 1.49-beta using rustup.rs
if [ ! -d "$HOME/.cargo" ]; then
  echo "Installing rust-beta ..."
  curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain beta -y
fi

librsvg のコンパイルエラー

これで librsvg がコンパイルできるかと思いましたができませんでした。調べてみると、Homebrew の superenv - Qiitaというものが設定されているため、PATH に ~/.cargo/bin を通していても無視するようです。ここで、--env=std をつけると設定した superenv を無視して、設定されたパスを使ってくれるということでした。

今度こそと試してみましたが、今度は error: no override and no default toolchain set というメッセージでコンパイルが止まってしまいました。brew のコンパイルでは sandbox-exec をする手前、個人のフォルダに入っている toolchain を見つけることができないのではないかと考えました。

rust Formula のリバースエンジニアリング

こうなると、rust の野良 brew を作るということになるのですが、rust-arm64.rb を作ろうとしても、beta 版の tarball のパスを調べることは困難でした。そこで、すでに .rustup の下にインストールされているファイルを rust Formula と同じ形で配置してしまうことを考えました。作戦が決まればリバースエンジニアリング開始です。

まずは Rosetta2 の brew で Intel 版の 1.48 stable をインストールしてみます。Intel 版なので、/usr/local にインストールされています。

hkob@hM1Air ~> arch --arch x86_64 brew_x86 install rust
==> Installing dependencies for rust: libssh2 and pkg-config
==> Installing rust dependency: libssh2
==> Pouring libssh2-1.9.0_1.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/libssh2/1.9.0_1: 184 files, 969.9KB
==> Installing rust dependency: pkg-config
==> Pouring pkg-config-0.29.2_3.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/pkg-config/0.29.2_3: 11 files, 656.6KB
==> Installing rust
==> Pouring rust-1.48.0.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/rust/1.48.0: 14,251 files, 558.0MB

ここで、brew list を使って、rust で何がインストールされているかを確認します。

hkob@hM1Air ~> arch --arch x86_64 brew_x86 list rust
/usr/local/Cellar/rust/1.48.0/.crates.toml
/usr/local/Cellar/rust/1.48.0/.crates2.json
/usr/local/Cellar/rust/1.48.0/bin/cargo
/usr/local/Cellar/rust/1.48.0/bin/rust-gdb
/usr/local/Cellar/rust/1.48.0/bin/rust-gdbgui
/usr/local/Cellar/rust/1.48.0/bin/rust-lldb
/usr/local/Cellar/rust/1.48.0/bin/rustc
/usr/local/Cellar/rust/1.48.0/bin/rustdoc
/usr/local/Cellar/rust/1.48.0/etc/bash_completion.d/cargo.bashcomp.sh
/usr/local/Cellar/rust/1.48.0/lib/libchalk_derive-97d218325ef82204.dylib
/usr/local/Cellar/rust/1.48.0/lib/librustc_driver-3640549726d24237.dylib
/usr/local/Cellar/rust/1.48.0/lib/librustc_macros-3d08af3a460c63ca.dylib
/usr/local/Cellar/rust/1.48.0/lib/libstd-93fc378b6b7db88c.dylib
/usr/local/Cellar/rust/1.48.0/lib/libtest-7ec4a3c03eb88004.dylib
/usr/local/Cellar/rust/1.48.0/lib/libtracing_attributes-159b2b2525b4554d.dylib
/usr/local/Cellar/rust/1.48.0/lib/rustlib/ (38 files)
/usr/local/Cellar/rust/1.48.0/share/doc/ (14157 files)
/usr/local/Cellar/rust/1.48.0/share/man/ (34 files)
/usr/local/Cellar/rust/1.48.0/share/zsh/site-functions/_cargo

これらのファイルが /usr/local のどこにリンクが貼られているかを brew link -v で確認します。link するために、一度 brew unlink して、再度リンクを verbose モードで実施しました。

hkob@hM1Air ~> arch --arch x86_64 brew_x86 link -v rust
Linking /usr/local/Cellar/rust/1.48.0...
ln -s ../../Cellar/rust/1.48.0/etc/bash_completion.d/cargo.bashcomp.sh cargo.bashcomp.sh
ln -s ../Cellar/rust/1.48.0/bin/cargo cargo
ln -s ../Cellar/rust/1.48.0/bin/rust-gdb rust-gdb
ln -s ../Cellar/rust/1.48.0/bin/rust-gdbgui rust-gdbgui
ln -s ../Cellar/rust/1.48.0/bin/rust-lldb rust-lldb
ln -s ../Cellar/rust/1.48.0/bin/rustc rustc
ln -s ../Cellar/rust/1.48.0/bin/rustdoc rustdoc
ln -s ../../Cellar/rust/1.48.0/share/doc/rust rust
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-bench.1 cargo-bench.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-build.1 cargo-build.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-check.1 cargo-check.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-clean.1 cargo-clean.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-doc.1 cargo-doc.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-fetch.1 cargo-fetch.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-fix.1 cargo-fix.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-generate-lockfile.1 cargo-generate-lockfile.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-help.1 cargo-help.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-init.1 cargo-init.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-install.1 cargo-install.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-locate-project.1 cargo-locate-project.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-login.1 cargo-login.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-metadata.1 cargo-metadata.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-new.1 cargo-new.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-owner.1 cargo-owner.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-package.1 cargo-package.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-pkgid.1 cargo-pkgid.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-publish.1 cargo-publish.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-run.1 cargo-run.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-rustc.1 cargo-rustc.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-rustdoc.1 cargo-rustdoc.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-search.1 cargo-search.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-test.1 cargo-test.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-tree.1 cargo-tree.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-uninstall.1 cargo-uninstall.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-update.1 cargo-update.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-vendor.1 cargo-vendor.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-verify-project.1 cargo-verify-project.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-version.1 cargo-version.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo-yank.1 cargo-yank.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/cargo.1 cargo.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/rustc.1 rustc.1
ln -s ../../../Cellar/rust/1.48.0/share/man/man1/rustdoc.1 rustdoc.1
ln -s ../../../Cellar/rust/1.48.0/share/zsh/site-functions/_cargo _cargo
ln -s ../Cellar/rust/1.48.0/lib/libchalk_derive-97d218325ef82204.dylib libchalk_derive-97d218325ef82204.dylib
ln -s ../Cellar/rust/1.48.0/lib/librustc_driver-3640549726d24237.dylib librustc_driver-3640549726d24237.dylib
ln -s ../Cellar/rust/1.48.0/lib/librustc_macros-3d08af3a460c63ca.dylib librustc_macros-3d08af3a460c63ca.dylib
ln -s ../Cellar/rust/1.48.0/lib/libstd-93fc378b6b7db88c.dylib libstd-93fc378b6b7db88c.dylib
ln -s ../Cellar/rust/1.48.0/lib/libtest-7ec4a3c03eb88004.dylib libtest-7ec4a3c03eb88004.dylib
ln -s ../Cellar/rust/1.48.0/lib/libtracing_attributes-159b2b2525b4554d.dylib libtracing_attributes-159b2b2525b4554d.dylib
ln -s ../Cellar/rust/1.48.0/lib/rustlib rustlib
50 symlinks created

確認できたので、rust および関連でインストールされた pkg-config, libssh2 を削除します。

arch --arch x86_64 brew_x86 uninstall rust
arch --arch x86_64 brew_x86 uninstall pkg-config libssh2

rust beta のフォルダ構成の確認

ここで、$HOME/.rustup/toolchains/beta-aarch64-apple-darwin のフォルダ構成と比較します。

hkob@hM1Air ~/.r/t/beta-aarch64-apple-darwin> find . -type f -print
./bin/rustdoc
./bin/cargo
./bin/clippy-driver
./bin/rust-gdbgui
./bin/rust-lldb
./bin/cargo-clippy
./bin/rustc
./bin/cargo-fmt
./bin/rustfmt
./bin/rust-gdb
./etc/bash_completion.d/cargo
./lib/rustlib/manifest-rust-std-aarch64-apple-darwin
./lib/rustlib/manifest-clippy-preview-aarch64-apple-darwin
./lib/rustlib/aarch64-apple-darwin/bin/rust-lld
./lib/rustlib/aarch64-apple-darwin/lib/libprofiler_builtins-8cd5d7a49915f347.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libgetopts-5938f1e18d91ac9a.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libunwind-5c4568ce399a1ac6.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libstd-fb92146976358ada.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libgimli-8808255652f9fb1e.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libpanic_unwind-1a980f3f9f4d2496.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libcompiler_builtins-599297c08cf4e309.rlib
./lib/rustlib/aarch64-apple-darwin/lib/liblibc-6277ce3c4f9565ca.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libtest-57a3dd85bf3a66f3.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libproc_macro-5a5e33eb413ba2a3.rlib
./lib/rustlib/aarch64-apple-darwin/lib/librustc_std_workspace_core-d786e5a700f40e71.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libcfg_if-6e5804dfdd49bfe7.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libstd-fb92146976358ada.dylib
./lib/rustlib/aarch64-apple-darwin/lib/liballoc-4e88f8eccf13cb06.rlib
./lib/rustlib/aarch64-apple-darwin/lib/librustc_std_workspace_alloc-e6361ce0a3a7e57a.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libtest-57a3dd85bf3a66f3.dylib
./lib/rustlib/aarch64-apple-darwin/lib/libminiz_oxide-23db372741135ce1.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libterm-79c0eec85296adf4.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libobject-aef43015d2e37ee0.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libaddr2line-9c0215ae58a8f126.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libadler-a1c85ab61273c673.rlib
./lib/rustlib/aarch64-apple-darwin/lib/librustc_demangle-257f812d85eafca4.rlib
./lib/rustlib/aarch64-apple-darwin/lib/librustc_std_workspace_std-a298a9fa2b4358aa.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libhashbrown-87a6a4e1ef91bbdf.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libunicode_width-d13da60bd092a62c.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libpanic_abort-2ff1715a996a2224.rlib
./lib/rustlib/aarch64-apple-darwin/lib/libcore-f357a5f6f2a76d4d.rlib
./lib/rustlib/etc/gdb_providers.py
./lib/rustlib/etc/lldb_commands
./lib/rustlib/etc/gdb_load_rust_pretty_printers.py
./lib/rustlib/etc/rust_types.py
./lib/rustlib/etc/lldb_lookup.py
./lib/rustlib/etc/lldb_providers.py
./lib/rustlib/etc/gdb_lookup.py
./lib/rustlib/multirust-channel-manifest.toml
./lib/rustlib/rust-installer-version
./lib/rustlib/manifest-rustc-aarch64-apple-darwin
./lib/rustlib/multirust-config.toml
./lib/rustlib/components
./lib/rustlib/manifest-rustfmt-preview-aarch64-apple-darwin
./lib/rustlib/manifest-cargo-aarch64-apple-darwin
./lib/libchalk_derive-b6546ec3dd9d440a.dylib
./lib/libtracing_attributes-88dfc0f8a9ccf25a.dylib
./lib/libstd-fb92146976358ada.dylib
./lib/libtest-57a3dd85bf3a66f3.dylib
./lib/librustc_driver-cba1fe2bb3f1909c.dylib
./lib/librustc_macros-4215e8aab5ed3aeb.dylib
./share/man/man1/cargo-doc.1
./share/man/man1/cargo-init.1
./share/man/man1/cargo-build.1
./share/man/man1/cargo-clean.1
./share/man/man1/cargo.1
./share/man/man1/rustdoc.1
./share/man/man1/rustc.1
./share/man/man1/cargo-pkgid.1
./share/man/man1/cargo-new.1
./share/man/man1/cargo-rustc.1
./share/man/man1/cargo-metadata.1
./share/man/man1/cargo-version.1
./share/man/man1/cargo-install.1
./share/man/man1/cargo-uninstall.1
./share/man/man1/cargo-rustdoc.1
./share/man/man1/cargo-bench.1
./share/man/man1/cargo-verify-project.1
./share/man/man1/cargo-run.1
./share/man/man1/cargo-test.1
./share/man/man1/cargo-generate-lockfile.1
./share/man/man1/cargo-vendor.1
./share/man/man1/cargo-check.1
./share/man/man1/cargo-search.1
./share/man/man1/cargo-fetch.1
./share/man/man1/cargo-update.1
./share/man/man1/cargo-tree.1
./share/man/man1/cargo-fix.1
./share/man/man1/cargo-login.1
./share/man/man1/cargo-yank.1
./share/man/man1/cargo-publish.1
./share/man/man1/cargo-locate-project.1
./share/man/man1/cargo-help.1
./share/man/man1/cargo-owner.1
./share/man/man1/cargo-package.1
./share/doc/cargo/LICENSE-THIRD-PARTY
./share/doc/cargo/LICENSE-APACHE
./share/doc/cargo/README.md
./share/doc/cargo/LICENSE-MIT
./share/doc/rust/LICENSE-APACHE
./share/doc/rust/README.md
./share/doc/rust/COPYRIGHT
./share/doc/rust/LICENSE-MIT
./share/doc/clippy/LICENSE-APACHE
./share/doc/clippy/README.md
./share/doc/clippy/LICENSE-MIT
./share/doc/rustfmt/LICENSE-APACHE
./share/doc/rustfmt/README.md
./share/doc/rustfmt/LICENSE-MIT
./share/zsh/site-functions/_cargo

ほぼ構成一緒ですね。これらを /opt/homebrew の中に同じような形でシンボリックリンクを貼ればいいはずです。

rust beta の /opt/homebrew 配下へのインストール

先程のインストール部分の後ろに /opt/homebrew へのシンボリックリンクを貼る処理を追加しました。実際にこれで ./bootstrap.sh を実行しました。このシンボリックリンクにより ~/.cargo/bin を PATH に追加しなくても、rustc が動作することを確認しました。

# Install Rust 1.49-beta using rustup.rs
if [ ! -d "$HOME/.cargo" ]; then
  echo "Installing rust-beta ..."
  curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain beta -y
  LINK_FILES=$(cat <<FILE_END
bin/rustdoc
bin/cargo
bin/clippy-driver
bin/rust-gdbgui
bin/rust-lldb
bin/cargo-clippy
bin/rustc
bin/cargo-fmt
bin/rustfmt
bin/rust-gdb
etc/bash_completion.d/cargo
lib/rustlib
lib/libchalk_derive-b6546ec3dd9d440a.dylib
lib/libtracing_attributes-88dfc0f8a9ccf25a.dylib
lib/libstd-fb92146976358ada.dylib
lib/libtest-57a3dd85bf3a66f3.dylib
lib/librustc_driver-cba1fe2bb3f1909c.dylib
lib/librustc_macros-4215e8aab5ed3aeb.dylib
share/man/man1/cargo-doc.1
share/man/man1/cargo-init.1
share/man/man1/cargo-build.1
share/man/man1/cargo-clean.1
share/man/man1/cargo.1
share/man/man1/rustdoc.1
share/man/man1/rustc.1
share/man/man1/cargo-pkgid.1
share/man/man1/cargo-new.1
share/man/man1/cargo-rustc.1
share/man/man1/cargo-metadata.1
share/man/man1/cargo-version.1
share/man/man1/cargo-install.1
share/man/man1/cargo-uninstall.1
share/man/man1/cargo-rustdoc.1
share/man/man1/cargo-bench.1
share/man/man1/cargo-verify-project.1
share/man/man1/cargo-run.1
share/man/man1/cargo-test.1
share/man/man1/cargo-generate-lockfile.1
share/man/man1/cargo-vendor.1
share/man/man1/cargo-check.1
share/man/man1/cargo-search.1
share/man/man1/cargo-fetch.1
share/man/man1/cargo-update.1
share/man/man1/cargo-tree.1
share/man/man1/cargo-fix.1
share/man/man1/cargo-login.1
share/man/man1/cargo-yank.1
share/man/man1/cargo-publish.1
share/man/man1/cargo-locate-project.1
share/man/man1/cargo-help.1
share/man/man1/cargo-owner.1
share/man/man1/cargo-package.1
share/doc/cargo
share/doc/rust
share/doc/clippy
share/doc/rustfmt
share/zsh/site-functions/_cargo
FILE_END
  )
  for file in $LINK_FILES
  do
    rm -rf /usr/local/$file
    ln -sf $HOME/.rustup/toolchains/beta-aarch64-apple-darwin/$file /opt/homebrew/$file
  done
fi

plantuml までの道

ここまでできれば、あとは野良 brew を作ればいいだけです。以下の Formula を作成しました。 * librsvg-arm64: depends_on "rust" => :build を削除 * graphviz: depends_on "librsvg-arm64" に変更 * plantuml: depends_on "cask" => "zulu11-arm64" に変更。plantuml 内の java 呼び出し部を openjdk から zulu の /usr/bin/java に変更

今回は非常に大変でした。1日仕事になってしまいました。

前の記事: MacFuse および sshfs の断念 - M1 MacBook Air インストール覚書(20) - hkob’s blog

hkob.hatenablog.com