CentOS 7 に Ruby 3.1.3 がインストールできなかったら

Ruby 3.1.3 が出たので CentOS 7 にインストールしようとしたらできなかった。
その原因と解決方法について。

# 現象

以下のようにして rbenv で Ruby 3.1.3 をインストールしようとした。

```terminal
rbenv install 3.1.3
```

エラーが出てインストールできなかった（後述）。

なお，同時にリリースされた 2.7.7 はインストールできた。

（追記 2022-12-01）私は試していないが，同時にリリースされた 3.0.5 は 3.1.3 と同様だそう。

# 原因

CentOS 7 の gcc のバージョンが古かった。

```terminal
$ 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 というやつでよいようだ。以下のようにしてこれをインストールする：

```terminal
sudo yum install centos-release-scl
sudo yum install devtoolset-11
```

しかし，これだけではだめで，scl コマンドを用いて「一時的に devtoolset-11 を有効化する」ということをしなければならないらしい。
以下のようにする

```terminal
scl enable devtoolset-11 bash
```

`enable devtoolset-11` の部分が「devtoolset-11 を有効化する」ということらしいが，重要なのはその次の `bash` の部分。

この第三引数には，「devtoolset-11 を有効化したうえでやりたいこと」を書くらしい。
上の記述の場合，devtoolset-11 を有効化したうえで bash のサブシェルを起動することになる。以降の操作はそのサブシェル上で行われる。`exit` すればそのサブシェルを抜けて，元のシェルに戻る。

このことは以下のようにして確かめられる（見やすさのため，出力の一部を省いた）。

```terminal
$ 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 が無効の状態に戻る。
以下のようにして確かめられる（出力の一部を省略）。

```terminal
$ 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 をインストールする

前節のサブシェル上で

```terminal
rbenv install 3.1.3
```

とすると，ふつうにインストールできた。めでたし。

気をつけなければいけないのは，devtoolset は Ruby のインストールだけでなく，拡張ライブラリーのインストール時も必要，ということだ。

たとえば，Ruby の標準添付ライブラリーである cgi は，一部分が C 言語で書かれた「拡張ライブラリー」というものになっている。
これを

```terminal
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` とかでウェブ検索しても原因に行き当たらない。

で，ログファイルのありかがここには書かれているので，それを見てみる。
以下のようになっている（一部分を抜粋）：

```terminal
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: 備考: 未宣言の識別子は出現した各関数内で一回のみ報告されます
```

やっぱり分からんて。

ただ，ここに出てくるキーワードを適当に使ってウェブ検索していたら，以下の記事に行きあたった。

https://blog.cloud-mes.com/2022/11/25/fix-vm-core-dot-h-error-ruby-current-ec-undeclared-when-install-ruby-3-dot-1-3-or-3-dot-0-5/

これでようやく原因と解決方法が分かった次第。

インストール時に「コンパイラーが古いっす」とか言ってくれればいいのになあ。