こんにちは、エムスリーエンジニアリンググループの園田です。本記事は エムスリー Advent Calendar 2021 の 18 日目の記事です。
最近、業務 PC の Mac が壊れたので、M1 (Apple Silicon) Mac に乗り換えました。
自分が担当している一部システムでは EOL の古い ruby を利用しているシステムがまだ残っており、この記事はその際に M1 Mac に ruby 2.3.8 をインストールしたときの備忘録です。
先に結論
ruby のインストール自体は比較的簡単にできました。
でも native ビルドが必要な gem は gem ごとに対応が必要でしんどすぎるので、業務利用は諦めました。
ローカル環境では docker 使うようにしてます。*1
ざっくり手順
- openssl 1.0.2 のソースに darwin-arm64 のパッチを当ててインストール
- ruby-2.3.8 の tool/config.sub に arm64 のパッチを当てる
- configure オプションに色々追加で指定してビルドする
プレーンなソースからインストールする場合も、 rbenv
を使ってる場合も、 asdf
を使っている場合も configure
の --prefix
が異なるだけで、手順はほぼ同じです。
なお、筆者は asdf
でインストールしました。
openssl 1.0.2 インストール
ruby 2.3.8 は homebrew で入れられる openssl 1.1 系には対応していないので 1.0.2 をソースからインストールする必要があります。
ソースは OpenSSL の HP からダウンロードしました。
openssl を darwin-arm64 に対応させるパッチは Gist にありました。
wget https://www.openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz tar zxf openssl-1.0.2u.tar.gz curl -s https://gist.githubusercontent.com/felixbuenemann/5f4dcb30ebb3b86e1302e2ec305bac89/raw/b339a33ff072c9747df21e2558c36634dd62c195/openssl-1.0.2u-darwin-arm64.patch | patch -p0
パッチを当てたら Configure コマンドに darwin64-arm64-cc
を指定してビルド & インストールしました。インストール先のディレクトリは任意です(ここでは $HOME/libs/openssl-1.0.2u
にしています)。
cd openssl-1.0.2u ./Configure "darwin64-arm64-cc" shared zlib --prefix=$HOME/libs/openssl-1.0.2u make && make install
ruby 2.3.8 インストール
こちらもそのままだと aarch64-apple-darwin-arm64 に対応していないので、 tool/config.sub
にパッチを当てます。こちらはパッチ当てなくてもファイルをそのままダウンロードできるのでそれを使いました。
wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.8.tar.gz tar zxf ruby-2.3.8.tar.gz cd ruby-2.3.8/tool mv config.sub{,.bak} wget https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.sub cd ../
インストールした openssl 1.0.2 のパスをオプションで指定して configure
しました。
./configure \ --prefix=$HOME/.asdf/installs/ruby/2.3.8 \ --disable-install-doc \ --disable-install-rdoc \ --enable-shared \ --with-openssl-dir=$HOME/libs/openssl-1.0.2u
rbenv の場合は
--prefix=$(rbenv root)/versions/2.3.8
など
このオプションで make したら ffi でエラーが出ました。
closure.c:263:14: error: implicit declaration of function 'ffi_prep_closure' is invalid in C99 [-Werror,-Wimplicit-function-declaration] result = ffi_prep_closure(pcl, cif, callback, (void *)self);
RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC
を指定すればいいらしい(ruby-build
を利用する場合で、直接インストールする場合は RUBY_
を消して CFLAGS
にする)。
環境変数を追加して再度 configure
と make
実行。
make clean export CFLAGS=-DUSE_FFI_CLOSURE_ALLOC ./configure \ --prefix=$HOME/.asdf/installs/ruby/2.3.8 \ --disable-install-doc \ --disable-install-rdoc \ --enable-shared \ --with-openssl-dir=$HOME/libs/openssl-1.0.2u make && make install
asdf
は reshim
しないと認識されませんでした(rbenv
なら rehash
かな?)。
asdf reshim asdf local ruby 2.3.8 ruby -v > ruby 2.3.8p459 (2018-10-18 revision 65136) [-darwin20]
ここまで来たら後一歩ですね。
gem install bundler
OMG ...
/Users/ryohei-sonoda/.asdf/installs/ruby/2.3.8/lib/ruby/2.3.0/-darwin20/enc/utf_16le.bundle: warning: failed to load encoding (UTF-16LE); use ASCII-8BIT instead /Users/ryohei-sonoda/.asdf/installs/ruby/2.3.8/lib/ruby/2.3.0/-darwin20/enc/utf_16be.bundle: warning: failed to load encoding (UTF-16BE); use ASCII-8BIT instead ERROR: Loading command: install (ArgumentError) unknown encoding name: binary ERROR: While executing gem ... (NoMethodError) undefined method `invoke_with_build_args' for nil:NilClass
Encoding 関連なので readline かな・・・?と勘を頼りに --with-readline-dir
をつけて再ビルド。
brew install readline # 未インストールの場合 make clean; rm -rf $HOME/.asdf/installs/ruby/2.3.8 # 消さないとダメ export CFLAGS=-DUSE_FFI_CLOSURE_ALLOC ./configure \ --prefix=$HOME/.asdf/installs/ruby/2.3.8 \ --disable-install-doc \ --disable-install-rdoc \ --enable-shared \ --with-openssl-dir=$HOME/libs/openssl-1.0.2u \ --with-readline-dir=$(brew --prefix readline) make && make install asdf reshim gem install bundler > Fetching: bundler-2.2.33.gem (100%) > Successfully installed bundler-2.2.33 > 1 gem installed
いけた。
ruby インストール後のトラブル
bundler で SSL エラー
bundle install
すると SSL のエラーが出る。
Fetching source index from https://rubygems.org/ Retrying fetcher due to error (2/4): Bundler::Fetcher::CertificateFailureError Could not verify the SSL certificate for https://rubygems.org/. There is a chance you are experiencing a man-in-the-middle attack, but most likely your system doesn't have the CA certificates needed for verification. For information about OpenSSL certificates, see https://railsapps.github.io/openssl-certificate-verify-failed.html. To connect without using SSL, edit your Gemfile sources and change 'https' to 'http'.
最近よく見かけたエラーなのですぐに Let's Encrypt の古い CA を見ているのかなと推測。
ruby -ropenssl -e "p OpenSSL::X509::DEFAULT_CERT_FILE" > /Users/ryohei-sonoda/libs/openssl-1.0.2u/ssl/cert.pem ls /Users/ryohei-sonoda/libs/openssl-1.0.2u/ssl/cert.pem > ls: cannot access '/Users/ryohei-sonoda/libs/openssl-1.0.2u/ssl/cert.pem': No such file or directory
そもそも cert.pem がなかった。以下で解決。
ln -s /etc/ssl/cert.pem /Users/ryohei-sonoda/libs/openssl-1.0.2u/ssl/cert.pem
nokogiri ビルドエラー
当然のように出てくるビルドエラー。依存の libxml2
のビルドに失敗しているらしい。
ld: symbol(s) not found for architecture arm64
以下でいけた。
brew install libxml2 bundle config --local build.nokogiri --use-system-libraries bundle install
ffi ビルドエラー
Invalid configuration `arm64-apple-darwin20.6.0': machine `arm64-apple' not recognized configure: error: /bin/sh /Users/ryohei-sonoda/git/askdoctors/v2/vendor/bundle/ruby/2.3.0/gems/ffi-1.9.17/ext/ffi_c/libffi/config.sub arm64-apple-darwin20.6.0 failed make: *** ["/Users/ryohei-sonoda/git/askdoctors/v2/vendor/bundle/ruby/2.3.0/gems/ffi-1.9.17/ext/ffi_c/libffi--darwin20"/.libs/libffi_convenience.a] Error 1
こちらは以下でいけました。
brew install libffi # 未インストールの場合 export LDFLAGS=-L$(brew --prefix libffi)/lib export CPPFLAGS=-I$(brew --prefix libffi)/include export PKG_CONFIG_PATH=$(brew --prefix libffi)/lib/pkgconfig bundle install
pg ビルドエラー
古い pg (0.18.2) でビルドエラー。
エラー内容は紛失したので書けませんが、以下でいけました。
bundle config --local \ build.pg \ --with-cflags=-Wno-error=implicit-function-declaration
byebug ビルドエラー
以下略・・・
まとめ
古い gem はほとんどが aarch64-apple-darwin-arm64
に対応していないので、諦めて docker 版の ruby 2.3 を使うことにしました。
docker イメージだとアーキテクチャが darwin/arm64 じゃなくて linux/arm64 になるので、だいたいの gem はビルドできるようだ
古い ruby を M1 Mac にインストールすることは「できる」けど、「できる」ことと「実用に足る」かどうかは別物であることを改めて思い知りました(それはそう)。
頑張って古い ruby をインストールしようとしている人が、この記事を見て思いとどまってくれたら幸いです。
参考にしたサイト
We are hiring!
古いアーキテクチャを刷新したいエネルギッシュなエンジニアを募集しています!もちろん、新しいアーキテクチャも扱ってます!(他のポストを見てればわかりますよね?)
*1:余談ですが、M1 Mac の docker volume は少し速くなった気がします。気のせいかな?