Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

M1 MacでRuby 2.4〜3.2をrbenvでビルドする最小限のセットアップを全部調べた

🔗 M1 MacでRuby 2.4〜3.2をrbenvでビルドするための要点

要点から先に書きます。

基本的には、以下の公式ドキュメントの記載通りにすればビルドできます。

参考: Building Ruby -- ruby/building_ruby.md at master · ruby/ruby

ビルドで使うOpenSSLについては以下に注意してください。

  • Ruby 3.1以降: OpenSSL 3系とOpenSSL 1.1.1系の両方が使える
  • Ruby 2.4〜3.0: OpenSSL 1.1.1系が必要

ただし、OpenSSL 1.1.1は2023/09/11にEOLとなり、以後のアップデートには有償サポートが必要です↓。特に業務で古いRubyのビルドが必要な場合はご注意ください。

参考: OpenSSL 1.1.1 End of Life - OpenSSL Blog

Ruby 3.0とOpenSSL 1.1.1の関連については、Rubyコミッターのhsbtさんによる記事がおすすめです↓。

参考: Ruby 3.0 がセキュリティメンテナンスフェーズになったのでいくつか補足 - HsbtDiary(2023-03-31)

OpenSSLの最も細かいバージョンは割と変わりやすいので、本記事では基本的にそれぞれ3系と1.1.1系と表記します。

🔗 ビルドでハマっている人のための最小ビルドオプション

公式ドキュメントの記載通りにすればビルドできると書きましたが、環境のセットアップによってはハマることがあります。

インストールでハマる場合、現在のbashの環境変数セットアップで何かをしくじっている可能性があります。私も.profileでの環境設定が適切でなかったためにハマりました😅。

忙しい人向けに、そうした既存のセットアップを一時的に上書きすることで確実にビルドできるビルドオプションを手短にまとめました。

🔗 ざっくりとした前提

詳しい前提については後述します

  • M1 MacBook環境(検証できませんでしたが、Intel Macなどでも使えると思います)
  • bash環境であること
  • Homebrew自身のインストールとHomebrew用の環境変数のセットアップ↓が終わっていること
  • gitrbenvruby-buildがインストールされて利用可能な状態であること
  • ビルドに必要なライブラリやツールが「Homebrewでインストールするもの」に示したとおりにHomebrewでインストールされていること
  • コンパイラはCommand Line Toolsを使いました(他のコンパイラでもよいはずです)
# Homebrew用の環境変数セットアップ
eval "$(/opt/homebrew/bin/brew shellenv)"
export LDFLAGS="-L$HOMEBREW_PREFIX/lib"

なお、HOMEBREW_PREFIXevalで自動的に設定されます。

追記

Command Line Toolsが古くなっているとconfigure: error: C compiler cannot create executablesエラーになる可能性があります。その場合は以下を実行してCommand Line Toolsを再インストールしましょう。

sudo rm -rf /Library/Developer/CommandLineTools
sudo xcode-select --install

🔗 A: Ruby 2.7〜3.2をビルドする場合

  • シェルで以下を実行する
# あえてbrew shellenvのevalを現在のbashでのみ再実行する
eval "$(/opt/homebrew/bin/brew shellenv)"
# 現在のbashでのみbisonパスを設定する
export PATH="$HOMEBREW_PREFIX/opt/bison/bin:$PATH"
# 現在のbashでのみLDFLAGSを上書きする
export LDFLAGS="-L$HOMEBREW_PREFIX/lib"

# 邪魔になりそうな環境変数を現在のbashでのみクリアする
export CPPFLAGS=""
export optflags=""
export OPENSSL_CFLAGS=""
export RUBY_CONFIGURE_OPTS=""
# 続けて以下のいずれかを実行

# Ruby 3.2の場合の例
rbenv install 3.2.2
# Ruby 3.1の場合の例
rbenv install 3.1.4
# Ruby 3.0の場合の例
rbenv install 3.0.6
# Ruby 2.7の場合の例
rbenv install 2.7.8

ビルドが完了したら、シェルを終了して再起動します。

追記(2024/06/13)

その後、Ruby 3.0.xに限ってCommand Line Toolsでコンパイルするとエラーが発生するようになりました(他のRubyバージョンでは発生しませんでした)。

以下のようにコンパイラをgccに変更することでRuby 3.0.xをビルドできました。

brew install gcc
export CC=gcc
rbenv install 3.0.6

参考: rbenv install 3.0.4 fails on macOS 13.3.1 · rbenv/ruby-build · Discussion #2185

🔗 B: Ruby 2.4〜2.6をビルドする場合

# あえてbrew shellenvのevalを現在のbashでのみ再実行する
eval "$(/opt/homebrew/bin/brew shellenv)"
# 現在のbashでのみbisonパスを設定する
export PATH="$HOMEBREW_PREFIX/opt/bison/bin:$PATH"
# 現在のbashでのみLDFLAGSを上書きする
export LDFLAGS="-L$HOMEBREW_PREFIX/lib"
# Ruby 2.4〜2.6で必要なオプション
export RUBY_CFLAGS="-w"

# 邪魔になりそうな環境変数を現在のbashでのみクリアする
export CPPFLAGS=""
export optflags=""
export OPENSSL_CFLAGS=""
export RUBY_CONFIGURE_OPTS=""

追記(2023-07-10)

その後Ruby 2.4.10のOpenSSLを1.1.1uにアップグレードするためインストールすると、ffi_prep_closureでエラーが発生しました。
RUBY_CFLAGSを以下のように変更することでインストールできました。

export RUBY_CFLAGS="-w -DUSE_FFI_CLOSURE_ALLOC"

参考: error: implicit declaration of function 'ffi_prep_closure' on M1 macOS Big Sur · Issue #869 · ffi/ffi

# 続けて以下のいずれかを実行

# Ruby 2.6の場合の例
rbenv install 2.6.8
# Ruby 2.5の場合の例
rbenv install 2.5.9
# Ruby 2.4の場合の例
rbenv install 2.4.10

ビルドが完了したら、シェルを終了して再起動します。

なお、Ruby 2.4〜2.6の場合の違いはexport RUBY_CFLAGS="-w"を追加していることだけです。

🔗 参考: ビルド内容をチェックする方法

irb -r rbconfigでIRBを起動してから、RbConfig::CONFIGのキーを指定することで、ビルドの詳細な内容を表示できます。この方法は、今回試したすべてのRubyバージョンで使えます。

たとえばRbConfig::CONFIG['configure_args']でビルドに指定したオプションを表示できます。

$ irb -r rbconfig
irb(main):001:0> RbConfig::CONFIG['configure_args']
=> " '--prefix=/Users/hachi8833/.anyenv/envs/rbenv/versions/2.4.10' '--with-openssl-dir=/Users/hachi8833/.anyenv/envs/rbenv/versions/2.4.10/openssl' '--enable-shared' '--with-readline-dir=/opt/homebrew/opt/readline' '--with-libyaml-dir=/opt/homebrew/opt/libyaml' '--with-gmp-dir=/opt/homebrew/opt/gmp' 'CC=clang' 'CFLAGS= -w' 'LDFLAGS=-L/Users/hachi8833/.anyenv/envs/rbenv/versions/2.4.10/lib -L/opt/homebrew/lib' 'CPPFLAGS=-I/Users/hachi8833/.anyenv/envs/rbenv/versions/2.4.10/include  -I /opt/homebrew/include -I/opt/homebrew/opt/libpq/include -I/opt/homebrew/opt/sqlite/include -I/opt/homebrew/opt/binutils/include'"

たとえばCPPFLAGSのオプションを知るにはRbConfig::CONFIG['CPPFLAGS']で表示できます。

$ irb -r rbconfig
irb(main):001:0> RbConfig::CONFIG['CPPFLAGS']
=> "-I/Users/hachi8833/.anyenv/envs/rbenv/versions/3.2.2/include  -I /opt/homebrew/include -I/opt/homebrew/opt/libpq/include -I/opt/homebrew/opt/sqlite/include -I/opt/homebrew/opt/binutils/include -I/opt/homebrew/opt/gmp/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT  "

たとえばjemallocが有効かどうかを知るにはRbConfig::CONFIG['MAINLIBS']で表示できます。

irb -r rbconfig
irb(main):001:0> RbConfig::CONFIG['MAINLIBS']
=> "-ljemalloc -lgmp -ldl -lobjc -lpthread "

参考: ubuntu - How to check ruby-2.6.3 is using jemalloc ? I installed ruby-2.6.3 as $ rvm install 2.6.3 -C --with-jemalloc - Stack Overflow

また、OpenSSLのバージョンはIRBで以下を実行するとチェックできます。

require 'openssl'
puts OpenSSL::OPENSSL_VERSION

参考: Rubyから使用しているOpenSSLのバージョン確認

🔗 詳細

ここからは読みたい人だけ読めばよいと思います。

以下は最小限のRubyビルドを確かめた結果です。YJITやjemalloc、--disable-install-docなどのオプションは含めていません。

環境変数の具体的な設定方法については省略します。私は環境変数のセットアップを.profileに書いていますが、人によっては.bashrcなどに書いていたりするかもしれません。詳しくは以下の記事をどうぞ。

Bash: .bashrcと.bash_profileの違いを今度こそ理解する

Homebrew以外のパッケージ管理(MacPortsなど)や、rbenv以外のRubyバージョン管理(rvmやadsfなど)については本記事では試していません🙏

🔗 環境

バージョン表示方法もメモします。

マシン
M1 MacBook Pro 2021
macOS
Ventura 13.2.1
シェル: bash 3.2.57(1)-release (arm64-apple-darwin22)
bash --version
CommandLine Tools: 14.2.0.0.1.1668646533
14.3.0.0.1.1679647830
pkgutil --pkg-info=com.apple.pkg.CLTools_Executables
Git 2.39.2
git --version
Ruby: 3.2.2 (2023-03-30 revision e51014f9c0) +YJIT [arm64-darwin22](ビルドで使われるカレントのRuby)
ruby --version
Homebrew 4.0.6
brew --version
rbenv 1.2.0-16-gc4395e5
rbenv --version
ruby-build RUBY_BUILD_VERSION="20230330"
Release ruby-build 20230330 · rbenv/ruby-build

rbenvとruby-buildのセットアップについては省略します。インストールについては以下を参考にしてください。

参考: Rails Girls - Japanese

🔗 Homebrewでインストールするもの

以下を実行してからシェルを再起動します。

$ brew install readline libyaml bison gperf zlib libffi

OpenSSLもインストールする場合は以下を実行してからシェルを再起動します。

$ brew install openssl@3 openssl@1.1 readline libyaml bison gperf zlib libffi

以下は参考までにバージョンを示します。

🔗 必須

openssl@3
stable 3.1.0 (bottled) [keg-only]
openssl@1.1
stable 1.1.1t (bottled) [keg-only]

後述するように、rbenvを使う場合はOpenSSLが自動ダウンロードされるので、HomebrewでインストールしなくてもOKです。
openssl@3openssl@1.1はHomebrewで両方インストールしておくことも可能ですが、環境変数はどちらか一方だけを指定する必要があります。

libyaml
stable 0.2.5 (bottled)
zlib
stable 1.2.13 (bottled), HEAD [keg-only]

🔗 Gitリポジトリからのビルドで必要なもの

autoconf
stable 2.71 (bottled)
bison(Ruby 3.2で必要)
stable 3.8.2 (bottled) [keg-only]
gperf
(なくてもいいらしいけど念のためインストール)
stable 3.1 (bottled)

🔗 オプション

readline
stable 8.2.1 (bottled) [keg-only]
libffi
stable 3.4.4 (bottled), HEAD [keg-only]
gmp
stable 6.2.1 (bottled), HEAD

🔗 参考: rbenvによるOpenSSLの自動ダウンロード

細かい話ですが、rbenvでRubyをビルドする場合、ローカル環境にOpenSSLがなければ自動インストールされます。Ruby 3.1以上なら自動的にOpenSSL 3系を、Ruby 2.4〜3.0では自動的にOpenSSL 1.1.1系をダウンロードします。

通常はこれで十分でしょう。

ビルドを頻繁に行うのであれば、HomebrewでOpenSSLをインストールしておけば、ダウンロードの時間を節約できます。

インストールするならbrew install openssl@3またはbrew install openssl@1.1のどちらかをインストールし、以下のいずれかをセットアップします。

# OpenSSL@3 の場合のセットアップ
export PATH="$HOMEBREW_PREFIX/opt/openssl@3/bin:$PATH"
export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/opt/openssl@3/lib/pkgconfig"
export RUBY_CONFIGURE_OPTS="$RUBY_CONFIGURE_OPTS --enable-yjit --with-openssl-dir=$HOMEBREW_PREFIX/opt/openssl@3"
# OpenSSL@1.1 の場合のセットアップ
export PATH="$HOMEBREW_PREFIX/opt/openssl@1.1/bin:$PATH"
export PKG_CONFIG_PATH="$HOMEBREW_PREFIX/opt/openssl@1.1/lib/pkgconfig"
export RUBY_CONFIGURE_OPTS="$RUBY_CONFIGURE_OPTS --with-openssl-dir=$HOMEBREW_PREFIX/opt/openssl@1.1"

Homebrewでは両方のバージョンをインストールしても構いませんが、環境変数セットアップには2つのバージョンを混ぜないようご注意ください。

🔗 参考: bison 3について

新しめのRubyでは、bison 3をHomebrewでインストールしたうえで、以下のパスを設定する必要があります。なお、Ruby 2.4〜3.2はすべてbison 3で問題なくビルドできました。

export PATH="$HOMEBREW_PREFIX/opt/bison/bin:$PATH"

参考: RubyをVisual C++でビルドする 2022.04版(+2022.12追記)

追記(2023/12/15)

Ruby 3.3からはbisonがlramaに置き換わるため、bisonのセットアップは不要になります。

参考: Ruby 3.3.0-rc1 リリース

ruby/lrama - GitHub

🔗 ビルドの結果

以下はビルドの記録です。どのRubyバージョンについても最新バージョンのみビルドを確認しました。

🔗 Ruby 3.1〜3.2

$ rbenv install 3.2.2
# 略
$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0)
$ rbenv install 3.1.4
# 略
$ ruby -v
ruby ruby 3.1.4p223 (2023-03-30 revision 957bb7cb81) [arm64-darwin22]
  • OpenSSLのパスを設定しない場合: ビルド成功
    • rbenvがOpenSSL 3.1.xを自動ダウンロードします
  • OpenSSL 1.1.1をhomebrewでインストールしてパスを設定: ビルド成功
  • OpenSSL 3.1をhomebrewでインストールしてパスを設定: ビルド成功

なお、Ruby 3.2からは--disable-install-rdocが無効になったのでご注意ください。
ドキュメントのインストールを無効にするのであれば、RUBY_CONFIGURE_OPTS--disable-install-docを指定します。

# 使ったセットアップ(自動ダウンロードが前提)
# Homebrew -----------------------------------
eval "$(/opt/homebrew/bin/brew shellenv)"
export LDFLAGS="$LDFLAGS -L $HOMEBREW_PREFIX/lib"

# bison 3--------------------------------------
export PATH="$HOMEBREW_PREFIX/opt/bison/bin:$PATH"

Ruby 3.2でRust版YJITもビルドに含める方法について詳しくは、以下の記事をどうぞ。

Ruby 3.2.0-devをM1 Macbook Pro(Ventura)でビルドする

🔗 Ruby 2.7〜3.0

$ rbenv install 3.0.6
# 略
$ ruby -v
ruby ruby 3.0.6p216 (2023-03-30 revision 23a532679b) [arm64-darwin22]
$ rbenv install 2.7.8
# 略
$ ruby -v
ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [arm64-darwin22]
  • OpenSSLのパスを設定しない場合: ビルド成功
    • rbenvがOpenSSL 1.1.1を自動ダウンロードします
  • OpenSSL 1.1.1をhomebrewでインストールしてパスを設定: ビルド成功

Ruby 3.0から下のバージョンではOpenSSL 3系が使えないので、OpenSSL 1.1.1系が必要です。rbenvの自動ダウンロードもOpenSSL 1.1.1系になります。

参考: Bug #18658: Need openssl 3 support for Ubuntu 22.04 (Ruby 2.7.x and 3.0.x) - Ruby master - Ruby Issue Tracking System

# 使ったセットアップ(自動ダウンロードが前提)
# Homebrew -----------------------------------
eval "$(/opt/homebrew/bin/brew shellenv)"
export LDFLAGS="$LDFLAGS -L $HOMEBREW_PREFIX/lib"

# bison 3--------------------------------------
export PATH="$HOMEBREW_PREFIX/opt/bison/bin:$PATH"

🔗 Ruby 2.4〜2.6

$ rbenv install 2.6.8
# 略
$ ruby -v
ruby 2.6.8p205 (2021-07-07 revision 67951) [arm64-darwin22]
$ rbenv install 2.5.9
# 略
$ ruby -v
ruby 2.5.9p229 (2021-04-05 revision 67939) [-darwin22]
$ rbenv install 2.4.10
# 略
$ ruby -v
ruby 2.4.10p364 (2020-03-31 revision 67879) [-darwin22]
  • OpenSSLのパスを設定しない場合: ビルド成功
    • rbenvがOpenSSL 1.1.1を自動ダウンロードします
  • OpenSSL 1.1.1をhomebrewでインストールしてパスを設定: ビルド成功

2.4〜2.6では、export RUBY_CFLAGS="-w"を追加する必要があります。

# 使ったセットアップ(自動ダウンロードが前提)
# Homebrew -----------------------------------
eval "$(/opt/homebrew/bin/brew shellenv)"
export LDFLAGS="$LDFLAGS -L $HOMEBREW_PREFIX/lib"

# bison 3--------------------------------------
export PATH="$HOMEBREW_PREFIX/opt/bison/bin:$PATH"

# Ruby 2.6.x以下用
export RUBY_CFLAGS="-w"

🔗 おまけ1: Ruby 2.3

Ruby 2.3.xはOpenSSL 1.0.2uまでしか使えないようです。
しかしrbenvにOpenSSL 1.0.2uを自動ダウンロードさせてもエラーになります。いろんなオプションを試しましたが失敗しました。

以下の記事によると、Ruby 2.3のビルドについては、OpenSSL 1.0.2uをソースでインストールしたりM1用のパッチを当てるなどしてRubyそのものはビルドできたものの、C拡張を使うgemが動かなかったりしたそうです。

参考: M1 Mac に古い ruby をインストールしてみたけど業務利用を諦めた話 - エムスリーテックブログ

Ruby 2.3以前はDocker Hubから探して使う方が無難なようです。もちろんRubyをアップグレードするに越したことはないのですが。

参考: ruby - Official Image | Docker Hub

🔗 おまけ2: 不要だったオプション

以下の設定オプションは検索するとよく見かけますが、少なくとも今回試したRuby 3.2〜Ruby 2.4では不要でした。Command Line Tools以外のCコンパイラで必要になるのかもしれないと想像しています。

  • export optflags="-Wno-error=implicit-function-declaration"
  • export OPENSSL_CFLAGS=-Wno-error=implicit-function-declaration
  • RUBY_CONFIGURE_OPTS--enable-shared"を追加

🔗 参考

関連記事

Bash: .bashrcと.bash_profileの違いを今度こそ理解する

Ruby 3.2.0-devをM1 Macbook Pro(Ventura)でビルドする


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。