Ruby 3.1.3 が出たので CentOS 7 にインストールしようとしたらできなかった。
その原因と解決方法について。
現象
以下のようにして rbenv で Ruby 3.1.3 をインストールしようとした。
rbenv install 3.1.3
エラーが出てインストールできなかった(後述)。
なお,同時にリリースされた 2.7.7 はインストールできた。
(追記 2022-12-01)私は試していないが,同時にリリースされた 3.0.5 は 3.1.3 と同様だそう。
原因
CentOS 7 の gcc のバージョンが古かった。
$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
gcc というのは C コンパイラーの一つ。Ruby は C(など)で書かれており,rbenv を使ってインストールする場合はこれが必要になる。
対策
devtoolset とかいうやつを入れると,新しい gcc が使えるらしい(元の gcc と共存可能)。
devtoolset-11 を入れる
現時点(2022 年 11 月)では devtoolset-11 というやつでよいようだ。以下のようにしてこれをインストールする:
sudo yum install centos-release-scl
sudo yum install devtoolset-11
しかし,これだけではだめで,scl コマンドを用いて「一時的に devtoolset-11 を有効化する」ということをしなければならないらしい。
以下のようにする
scl enable devtoolset-11 bash
enable devtoolset-11
の部分が「devtoolset-11 を有効化する」ということらしいが,重要なのはその次の bash
の部分。
この第三引数には,「devtoolset-11 を有効化したうえでやりたいこと」を書くらしい。
上の記述の場合,devtoolset-11 を有効化したうえで bash のサブシェルを起動することになる。以降の操作はそのサブシェル上で行われる。exit
すればそのサブシェルを抜けて,元のシェルに戻る。
このことは以下のようにして確かめられる(見やすさのため,出力の一部を省いた)。
$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
$ scl enable devtoolset-11 bash
$ gcc --version
gcc (GCC) 11.2.1 20220127 (Red Hat 11.2.1-9)
$ exit
$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
exit
でサブシェルを抜けることで,gcc のバージョンが古いほうに戻ったことが見て取れる。
なお,やりたいことが「一つのコマンドを実行する」だけであれば,bash
の代わりにそれを書けばよい。" "
で囲めばスペースなどが入っていても大丈夫。
この場合,scl
の実行後は devtoolset が無効の状態に戻る。
以下のようにして確かめられる(出力の一部を省略)。
$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
$ scl enable devtoolset-11 "gcc --version"
gcc (GCC) 11.2.1 20220127 (Red Hat 11.2.1-9)
$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Ruby をインストールする
前節のサブシェル上で
rbenv install 3.1.3
とすると,ふつうにインストールできた。めでたし。
気をつけなければいけないのは,devtoolset は Ruby のインストールだけでなく,拡張ライブラリーのインストール時も必要,ということだ。
たとえば,Ruby の標準添付ライブラリーである cgi は,一部分が C 言語で書かれた「拡張ライブラリー」というものになっている。
これを
gem update cgi
で最新版にしようとしたとき,古い gcc だとエラーが出てインストールできない。
stringio なども同様。というか,標準添付ライブラリーって,拡張ライブラリーが多い。
gem をインストール,アップデートするたびに scl コマンドを叩くのは面倒なので,有効にしっぱなしにすることもできるようなのだが,まだ試していない。
インストール失敗時のエラー
古い gcc を使っていてインストールに失敗したときは,以下のようなエラーメッセージが出た。
To follow progress, use 'tail -f /tmp/ruby-build.20221128112424.16414.log' or pass --verbose
Downloading ruby-3.1.3.tar.gz...
-> https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.3.tar.gz
Installing ruby-3.1.3...
BUILD FAILED (CentOS Linux 7 using ruby-build 20220415-108-g4f4f307)
Inspect or clean up the working tree at /tmp/ruby-build.20221128112424.16414.uOztwE
Results logged to /tmp/ruby-build.20221128112424.16414.log
Last 10 log lines:
^
vm_core.h:1870:34: 備考: 未宣言の識別子は出現した各関数内で一回のみ報告されます
miniinit.c: トップレベル:
cc1: 警告: 認識できないコマンドラインオプション "-Wno-tautological-compare" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-self-assign" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-parentheses-equality" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-constant-logical-operand" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-cast-function-type" です [デフォルトで有効]
make: *** [miniinit.o] エラー 1
make: *** 未完了のジョブを待っています....
まあ,これ見ても素人にはなんのことかサッパリ分からん。
-Wno-tautological-compare
とかでウェブ検索しても原因に行き当たらない。
で,ログファイルのありかがここには書かれているので,それを見てみる。
以下のようになっている(一部分を抜粋):
compiling dmyext.c
translating probes probes.d
In file included from vm_core.h:83:0,
from iseq.h:14,
from mini_builtin.c:3,
from miniinit.c:51:
thread_pthread.h:108:43: エラー: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘struct’
RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER struct rb_execution_context_struct *ruby_current_ec;
^
In file included from iseq.h:14:0,
from mini_builtin.c:3,
from miniinit.c:51:
vm_core.h: 関数 ‘rb_current_execution_context’ 内:
vm_core.h:1870:34: エラー: ‘ruby_current_ec’ が宣言されていません (この関数内での最初の使用)
rb_execution_context_t *ec = ruby_current_ec;
^
vm_core.h:1870:34: 備考: 未宣言の識別子は出現した各関数内で一回のみ報告されます
やっぱり分からんて。
ただ,ここに出てくるキーワードを適当に使ってウェブ検索していたら,以下の記事に行きあたった。
これでようやく原因と解決方法が分かった次第。
インストール時に「コンパイラーが古いっす」とか言ってくれればいいのになあ。