M1 Mac (macOS Monterey) で therubyracer を運用することはできるのだろうか?
結論
therubyracer はもう捨てたほうが良い!
いろいろ試しましたが、M1 Mac で therubyracer と共存しながら正しくアプリケーションを動作させる方法は、少なくとも筆者の調べでは見つけることができませんでした……。
削除して大丈夫?
プロジェクトごとに環境はまちまちでしょうから、絶対に大丈夫とは言い難いですが、以下の記事に記載されているとおり、Node.js を実行できる環境であれば、ほとんどのケースでは therubyracer を削除しても問題なく動作します。
少なくとも筆者の関わっている Rails アプリケーションでは問題ありませんでした。
やることとしてはとてもシンプルで、Gemfile から gem 'therubyracer' の記述を削除して bundle install を実行するだけです。
Gemfile を使っていない場合は gem uninstall therubyracer を実行するだけです。
必要になるかもしれない手順
筆者はここ数日いろいろと試行錯誤している中で therubyracer を削除してもう一度ビルドし直したら動いてしまったので、もしかしたらその過程で必要だった手順があるのかもしれません。
そのため、それまでに行った作業を念のため共有しておきます。
Intel 版 v8 を削除
いくつかの記事では Intel 版の Homebrew で v8@3.15 をインストールするように書かれています。
しかしこれは結果的には不要だったので削除しました。
arch -x86_64 /usr/local/bin/brew uninstall v8@3.15
もしそれらの手順に従ってインストールしてしまった場合は上記のコマンドで削除してください。
ARM 版 v8 を追加
Intel 版 Homebrew の v8@3.15 を削除した代わりに、ARM 版 (M1 Mac 版) Homebrew で、バージョンを指定しない v8 をインストールしました。
brew install v8
ARM 版 Homebrew では v8@3.15 はインストールできませんが、v8 はインストールできます。
ただこれはあとから考えると必要だったのかどうかは不明です。いったん削除して最初から全部試すのも面倒なので検証はしていないです……。
不要な gem を削除
JS 周りの gem をいろいろ試したのですが、結局どれも M1 Mac では正しく動作しないどころか、これがインストールされているのが原因で勝手に使おうとして動いていなかった可能性もあります。
そのため、以下の gem が Gemfile に記述されている場合は、そのプロジェクトで使っていない限り削除したほうが良いかもしれません。
-gem 'libv8'
-gem 'libv8-node'
-gem 'therubyracer'
-gem 'mini_racer'
その後、bundle install も忘れずに実行してください。
bundle install
どこかで勝手に使われている可能性もあるので、単に Gemfile から削除するだけでなく、システムからも削除することをおすすめします。
gem uninstall libv8 libv8-node therubyracer mini_racer
おつかれさまでした
ここから先は単に therubyracer を M1 Mac で使うのが現実的ではないということを示すためだけの筆者のただの奮闘記ですので、時間に余裕のある方のみで大丈夫です。
インストール手順について
therubyracer のインストールには libv8 のインストールが必要で、libv8 のインストールには v8 が必要です。
つまり、v8 ← libv8 ← therubyracer という依存関係になっています。
このうち v8 は Homebrew でインストール、libv8 と therubyracer は gem でインストールします。
v8
なのでまずは Homebrew で v8 をインストールしようとしてみます。therubyracer で必要なのは v8@3.15 なのでこれをインストールします。
brew install v8@3.15
すると以下のエラーが発生します。
Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
M1 Mac では v8 はインストールできないようです。
幸い、M1 Mac にはこうした互換性の問題を解消するため、Rosetta 2 という仕組みがあります。これを利用することで Intel でしか動作しないアプリケーションやプログラムを動作させることができるようになります。
ということで、Intel 版の Homebrew をインストールし、そちら側から v8 をインストールしてみます。
まずは Intel 版の Homebrew をインストールします。
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
次に Intel 版の Homebrew で v8 をインストールします。
arch -x86_64 /usr/local/bin/brew install v8@3.15
無事インストールできました。
libv8
これで libv8 がインストールできるようになっているはずです。以下のコマンドを実行してインストールしてみます。
gem install libv8 -v '3.16.14.19' -- --with-system-v8
インストールできました。
bundle install からインストールする場合は bundle config で --with-system-v8 を設定しておく必要があります。
bundle config --local build.libv8 --with-system-v8
bundle install
therubyracer
これで therubyracer もインストールできるようになったはずです。
インストールする際には先ほどインストールした v8 のインストール先のパスを指定する必要があるのですが、ここで注意しなければいけないのは、Intel 版 Homebrew からインストールしたパスを指定する必要があるということです。
arch -x86_64 /usr/local/bin/brew --prefix v8@3.15
/usr/local/opt/v8@3.15
単に brew --prefix v8@3.15 とすると /opt/homebrew/opt/v8@3.15 という別のパスを指してしまうので注意してください。
Intel 版 Homebrew でインストールした v8 のパスを指定して therubyracer をインストールします。
gem install therubyracer -v '0.12.3' -- --with-v8-dir=$(arch -x86_64 /usr/local/bin/brew --prefix v8@3.15)
libv8 のときと同様、bundle install からインストールする場合は bundle config でオプションをあらかじめ設定しておく必要があります。
bundle config --local build.therubyracer --with-v8-dir=$(arch -x86_64 /usr/local/bin/brew --prefix v8@3.15)
bundle install
互換性問題
さて、これで問題なく therubyracer がインストールされたように思えます。厳密に言えば『インストール』自体はできているのですが、想定通りに動作しません。
とりあえず rake コマンドを実行してみます。
bundle exec rake routes
すると互換性がないというエラーが表示されてしまいます。理由は単純に ARM プロセッサで x86_64 用のプログラムを実行しようとしているから、だと思いますが、arch -x86_64 bundle exec rake routes としても同じエラーになってしまいます。
rake だけでなく rails などでも同じ原因を示すエラーが表示されます。
これを解決する方法が調べてもわからず、詰みました……。
mini_racer ならどうか?
therubyracer の代替として mini_racer という gem があります。
これは M1 Mac とも互換性があると言われているのでこちらも試してみてみました。
gem install mini_racer
しかし、こちらもインストール自体はできるのですが、symbol not found in flat namespace というエラーで使うことができませんでした。
余談ですが、このとき @scruff311 さんのコメント を見て mini_racer や libv8-node などを削除して、therubyracer や mini_racer などに依存せずにもう一度ビルドし直したらうまくいきました。
さいごに
M1 Mac で therubyracer が使われている Rails アプリケーションを正しく動作させる方法としてはこんなところでしょうか。
-
therubyracerをプロジェクトから削除する - フル Docker で環境構築する
個人的にはもう廃れている therubyracer を削除するという方針のほうがすっきりするかなあと思います。
謝辞
今回の件でいろいろと調べている間に伊藤淳一さんのツイートを見つけ、Twitter で質問させていただきました。therubyracer をどうにかするより使わずに済む方向で環境構築したほうが良いというアドバイスのもと、なんとか問題を解決することができました。ありがとうございます! 🙏
Discussion