GemのNokogiriを使おうとしたら`version `GLIBC_2.29' not found`エラーが出たときのことを調べた

## はじめに

以前、M1 Mac で Rails のセットアップをしているときに、

```console
ERROR: It looks like you're trying to use Nokogiri as a precompiled native gem on a system with glibc < 2.17:

  /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /usr/local/bundle/gems/nokogiri-1.13.6-aarch64-linux/lib/nokogiri/2.7/nokogiri.so) - /usr/local/bundle/gems/nokogiri-1.13.6-aarch64-linux/lib/nokogiri/2.7/nokogiri.so

  If that's the case, then please install Nokogiri via the `ruby` platform gem:
      gem install nokogiri --platform=ruby
  or:
      bundle config set force_ruby_platform true

  Please visit https://nokogiri.org/tutorials/installing_nokogiri.html for more help.
```

のようなエラーが発生しているのを見たので、調べてみた。

僕はM1 Macを持っていないので、ARMアーキテクチャのインスタンスで動かしているUbuntuで試してみた。

## 解決方法

Nokogiri のインストール時に、`--platform=ruby`をつけると解決する。

```console
$ gem install nokogiri --platform=ruby
```

bundler を使っている場合は、

```console
$ bundle config set force_ruby_platform true
```

を設定すると解決する。

↓ を参照。

https://github.com/sparklemotion/nokogiri.org/blob/main/docs/tutorials/installing_nokogiri.md#how-can-i-avoid-using-a-precompiled-native-gem

## 何が起こっているのか

Nokogiri の`1.11.0`からプリコンパイル済みでパッケージが配布されているのが原因そう。

エラーを見ると、

> ERROR: It looks like you're trying to use Nokogiri as a precompiled native gem on a system with glibc < 2.17:

と自分の環境とは別の環境でコンパイルされたのが原因であると書いている。

Nokogiri のソースコードを読んでみると、
https://github.com/sparklemotion/nokogiri/blob/main/lib/nokogiri/extension.rb

```ruby:lib/nokogiri/extension.rb
# load the C or Java extension
begin
  # native precompiled gems package shared libraries in <gem_dir>/lib/nokogiri/<ruby_version>
  ::RUBY_VERSION =~ /(\d+\.\d+)/
  require_relative "#{Regexp.last_match(1)}/nokogiri"
rescue LoadError => e
  if /GLIBC/.match?(e.message)
    warn(<<~EOM)

      ERROR: It looks like you're trying to use Nokogiri as a precompiled native gem on a system
             with an unsupported version of glibc.

      # 略...
    EOM
    raise e
  end

  # 略...
end
```

`lib/nokogiri`配下に現在使っている Ruby のバージョンのディレクトリがあり、その中にプリコンパイルされた共有ライブラリがある。

```console
$ pwd
/usr/local/bundle/gems/nokogiri-1.13.6-aarch64-linux/lib/nokogiri/2.7

$ ls -la
total 2376
drwxr-xr-x  2 root root    4096 May 20 00:00 .
drwxr-xr-x 14 root root    4096 May 20 00:00 ..
-rwxrwxr-x  1 root root 2422072 May 20 00:00 nokogiri.so
```

エラーでは`glibc`が2.17未満でプリコンパイルされたとのことなので、自分の環境の`glibc`を確認してみると、`2.28`。

```console
$ pwd
/usr/local/bundle/gems/nokogiri-1.13.6-aarch64-linux/lib/nokogiri/2.7

$ ldd nokogiri.so
./nokogiri.so: /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by ./nokogiri.so)
	linux-vdso.so.1 (0x0000ffff8fbcd000)
	libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000ffff8f881000)
	libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff8f70f000)
	/lib/ld-linux-aarch64.so.1 (0x0000ffff8fb9f000)

$ /lib/aarch64-linux-gnu/libc.so.6
GNU C Library (Debian GLIBC 2.28-10) stable release version 2.28.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 8.3.0.
libc ABIs: UNIQUE ABSOLUTE
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.
```

`--platform=ruby`をつけることで、プリコンパイル済みのパッケージを使わずにネイティブビルドをしてインストールすることができる。

`--platform=ruby`をつけてインストールしたあとに、見てみるとネイティブビルドされていることが確認できる。

```console
$ pwd
/usr/local/bundle/gems/nokogiri-1.13.6/ext/nokogiri

$ ls nokogiri.so
nokogiri.so
```

## Refs

- [Nokogiri が 1.11.0 からプリコンパイル済みで配布される - koic の日記](https://koic.hatenablog.com/entry/nokogiri-1-11-0-will-be-precompiled)
- [nokogiri.org/installing_nokogiri.md at main · sparklemotion/nokogiri.org](https://github.com/sparklemotion/nokogiri.org/blob/main/docs/tutorials/installing_nokogiri.md#how-can-i-avoid-using-a-precompiled-native-gem)
- [sparklemotion/nokogiri: Nokogiri (鋸) makes it easy and painless to work with XML and HTML from Ruby.](https://github.com/sparklemotion/nokogiri)
- [Feedback and final to-do items for precompiled native gems on Linux and OSX · Issue #2075 · sparklemotion/nokogiri](https://github.com/sparklemotion/nokogiri/issues/2075)
- [How do you precompile the native extensions for a ruby gem for linux? - Stack Overflow](https://stackoverflow.com/questions/3667918/how-do-you-precompile-the-native-extensions-for-a-ruby-gem-for-linux)
- [Bundler 経由で`--platform=ruby`指定の Gem をあえて入れたい場合](https://teratail.com/questions/25224)