🏎

M1 Mac (macOS Monterey) で therubyracer を運用することはできるのだろうか?

2022/09/23に公開

結論

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 をインストールするように書かれています。

しかしこれは結果的には不要だったので削除しました。

Shell
arch -x86_64 /usr/local/bin/brew uninstall v8@3.15

もしそれらの手順に従ってインストールしてしまった場合は上記のコマンドで削除してください。

ARM 版 v8 を追加

Intel 版 Homebrew の v8@3.15 を削除した代わりに、ARM 版 (M1 Mac 版) Homebrew で、バージョンを指定しない v8 をインストールしました。

Shell
brew install v8

ARM 版 Homebrew では v8@3.15 はインストールできませんが、v8 はインストールできます。

ただこれはあとから考えると必要だったのかどうかは不明です。いったん削除して最初から全部試すのも面倒なので検証はしていないです……。

不要な gem を削除

JS 周りの gem をいろいろ試したのですが、結局どれも M1 Mac では正しく動作しないどころか、これがインストールされているのが原因で勝手に使おうとして動いていなかった可能性もあります。

そのため、以下の gem が Gemfile に記述されている場合は、そのプロジェクトで使っていない限り削除したほうが良いかもしれません。

Gemfile
-gem 'libv8'
-gem 'libv8-node'
-gem 'therubyracer'
-gem 'mini_racer'

その後、bundle install も忘れずに実行してください。

Shell
bundle install

どこかで勝手に使われている可能性もあるので、単に Gemfile から削除するだけでなく、システムからも削除することをおすすめします。

Shell
gem uninstall libv8 libv8-node therubyracer mini_racer

おつかれさまでした

ここから先は単に therubyracer を M1 Mac で使うのが現実的ではないということを示すためだけの筆者のただの奮闘記ですので、時間に余裕のある方のみで大丈夫です。

インストール手順について

therubyracer のインストールには libv8 のインストールが必要で、libv8 のインストールには v8 が必要です。

つまり、v8libv8therubyracer という依存関係になっています。

このうち v8 は Homebrew でインストール、libv8therubyracer は gem でインストールします。

v8

なのでまずは Homebrew で v8 をインストールしようとしてみます。therubyracer で必要なのは v8@3.15 なのでこれをインストールします。

Shell
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 をインストールします。

Shell
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

次に Intel 版の Homebrew で v8 をインストールします。

Shell
arch -x86_64 /usr/local/bin/brew install v8@3.15

無事インストールできました。

libv8

これで libv8 がインストールできるようになっているはずです。以下のコマンドを実行してインストールしてみます。

Shell
gem install libv8 -v '3.16.14.19' -- --with-system-v8

インストールできました。

bundle install からインストールする場合は bundle config--with-system-v8 を設定しておく必要があります。

Shell
bundle config --local build.libv8 --with-system-v8
bundle install

therubyracer

これで therubyracer もインストールできるようになったはずです。

インストールする際には先ほどインストールした v8 のインストール先のパスを指定する必要があるのですが、ここで注意しなければいけないのは、Intel 版 Homebrew からインストールしたパスを指定する必要があるということです。

Shell
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 をインストールします。

Shell
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 でオプションをあらかじめ設定しておく必要があります。

Shell
bundle config --local build.therubyracer --with-v8-dir=$(arch -x86_64 /usr/local/bin/brew --prefix v8@3.15)
bundle install

互換性問題

さて、これで問題なく therubyracer がインストールされたように思えます。厳密に言えば『インストール』自体はできているのですが、想定通りに動作しません。

とりあえず rake コマンドを実行してみます。

Shell
bundle exec rake routes

すると互換性がないというエラーが表示されてしまいます。理由は単純に ARM プロセッサで x86_64 用のプログラムを実行しようとしているから、だと思いますが、arch -x86_64 bundle exec rake routes としても同じエラーになってしまいます。

rake だけでなく rails などでも同じ原因を示すエラーが表示されます。

これを解決する方法が調べてもわからず、詰みました……。

mini_racer ならどうか?

therubyracer の代替として mini_racer という gem があります。

これは M1 Mac とも互換性があると言われているのでこちらも試してみてみました。

Shell
gem install mini_racer

しかし、こちらもインストール自体はできるのですが、symbol not found in flat namespace というエラーで使うことができませんでした。

余談ですが、このとき @scruff311 さんのコメント を見て mini_racerlibv8-node などを削除して、therubyracermini_racer などに依存せずにもう一度ビルドし直したらうまくいきました。

さいごに

M1 Mac で therubyracer が使われている Rails アプリケーションを正しく動作させる方法としてはこんなところでしょうか。

  • therubyracer をプロジェクトから削除する
  • フル Docker で環境構築する

個人的にはもう廃れている therubyracer を削除するという方針のほうがすっきりするかなあと思います。

謝辞

今回の件でいろいろと調べている間に伊藤淳一さんのツイートを見つけ、Twitter で質問させていただきました。therubyracer をどうにかするより使わずに済む方向で環境構築したほうが良いというアドバイスのもと、なんとか問題を解決することができました。ありがとうございます! 🙏

https://twitter.com/i/web/status/1373956412120965122

参考サイト

GitHubで編集を提案

Discussion