3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Nokogiri が version `GLIBC_2.29' not found で読み込めない件

Last updated at Posted at 2024-12-26

はじめに

AlmaLinux 上で動いている,とある Rails プロジェクトにて。

Nokogiri のバージョンを 1.18.0 にしたところ,動かなくなった。
たとえば

rails -T

しただけで

/lib64/libm.so.6: version `GLIBC_2.29' not found (required by /usr/local/rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/nokogiri-1.18.0-x86_64-linux-gnu/lib/nokogiri/3.4/nokogiri.so) - /usr/local/rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/nokogiri-1.18.0-x86_64-linux-gnu/lib/nokogiri/3.4/nokogiri.so

とエラーが出る。

2022 年にも(各種バージョンは違うが)ほぼ同じ問題によって,あちこちで記事が書かれたようだ。

環境

  • OS ver. AlmaLinux release 8.10 (Cerulean Leopard) Kernel 4.18.0-553.33.1.el8_10.x86_64
  • ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
  • Bundler version 2.6.2

原因

nokogiri は C で書かれた部分を含む拡張ライブラリーだが,主要なプラットフォーム向けに,C 部分のコンパイル済みパッケージも用意されている。
(このあたり,正確な用語を知らないので,間違ってたら教えてください)

そのため,対応 OS ではインストール時にコンパイラーが走らなくてよい。

ところが,今回の問題は,そのコンパイル済みのやつがシステムの環境と合ってないために起きたようだ。

AlmaLinux 8.10 は glibc 2.28 がインストールされているらしい。
このことは dnf info glibc で確認できる。

一方,インストールした最新の nokogiri は

$ gem list nokogiri
*** LOCAL GEMS ***

nokogiri (1.18.0 x86_64-linux-gnu)

なのだが,こいつは glibc 2.29 を要求するらしい。惜しい,ぎりぎりダメじゃん。

Rails プロジェクトじゃなくても,単に

ruby -r nokogiri -e "puts Nokogiri::VERSION"

とやっただけで冒頭に掲げたエラーが出る。
(エラーメッセージの全体は長いが省略)

対策

エラーメッセージの中には,対処法がちゃんと書かれている。
私のように英語が苦手な人も,「あー,ゴチャゴチャなに言ってるかわかんねー,まーいーや,エラーメッセージでググっちゃえー」などと思わず,分からないなりに読もうとしてみるのがいいと思うよ。

件の「`GLIBC_2.29' not found」の直後に

  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

とあった。

要するに「platform を ruby として nokogiri をインストールしなはれ」と言っている。

これが何を意味するかというと,C 部分がコンパイル済みのやつをインストールするんじゃなくて,手元でコンパイルするようにインストールする,と。
(それがなんで「platform が ruby」なのかよく分からんが)

やり方としては

gem install nokogiri --platform=ruby

bundle config set force_ruby_platform true

と二つある,と。親切に具体的なコマンドまで書いてくれている。

まずは --platform=ruby

これは今までにも使ったことがあるオプションだ。

ではまず

gem uninstall nokogiri

でアンインストールしておいて,書かれているとおり

gem install nokogiri --platform=ruby

でインストール。
コンパイラーが走るので,約 1 分かかる。たるい。

この状態で Nokogiri が読めるか確認すると……

$ ruby -r nokogiri -e "puts Nokogiri::VERSION"
1.18.0

よっしゃー,解決!

……となれば話は簡単なのだが,Rails アプリ(に限らずなんらかのプロジェクト)でうっかり

bundle update

しようものなら,nokogiri 1.18.0 が入っているにもかかわらず,同バージョンのコンパイル済み版(nokogiri-1.18.0-x86_64-linux-gnu)が新たにインストールされてしまう。
ひ〜

force_ruby_platform 設定を試す

では次に

bundle config set force_ruby_platform true

を検討しよう。
よく分からんが,いかにも「platform=ruby を強制する」感じがする。

上記のコマンドを実行すると,Bundler の設定が変わるようだ。
この「設定」というのは,プロジェクトディレクトリー(Gemfile を置くところ)直下の .bundle/config と,ユーザーのホームディレクトリー直下の .bundle/config に書かれている(というか,そこから読み取るようになっている)。

これを,件の Rails アプリのディレクトリーで実行すると,その直下の .bundle/config

BUNDLE_FORCE_RUBY_PLATFORM: "true"

が追加された。
オプションなしでも,グローバルじゃなくてローカルの設定の変更になるのね。
(ちなみに,Gemfile の存在しないディレクトリーでやってみたら,.bundle/config は作られなかった。エラーも出なかった)

この状態なら

bundle update

しても,「コンパイル済み版」がインストールされたりはしなかった。
めでたしめでたし。

しかし,これをやると,nokogiri だけでなく全部の gem で「自前コンパイル」になるんだよな? マジかよ。

glibc をバージョンアップするのは?

2022 年に多数書かれた記事の情報によると,glibc のバージョンを上げよう,という方向の解決方法はダメぽい(OS にがっつり噛んでいるので)。

AlmaLinux 8 はメンテナンスサポートが 2029 年 3 月 1 日までと長く使えるので安心していたが,こういうところでトラブルがいろいろ生じるのだろうなあ。

ちなみに AlmaLinux 9.5 で確認したところ,glibc のバージョンは 2.34 なので,こちらは余裕で大丈夫。

感想

  • 疲れた。
  • gem 1 個のインストールに 1 分もかかる(nokogiri の場合)のは嫌だな。
  • この設定で全ての gem についてコンパイル済みが利用できなくなるのは嫌だな。
  • gem のインストール時には何も起こらず,require で初めて問題が起きるのは嫌だな。
  • AlmaLinux のサポート期間が長いのはいいけど,こういう問題を回避するためにアップデートを検討しなければならないとは……。

追記 2025-01-07

Nokogiri のリポジトリーに本件の issue が立っていた(すでにクローズされている):
[bug] v1.18.x requiring glibc 2.29 (Rocky 8.10 ships with 2.28) · Issue #3399 · sparklemotion/nokogiri

直接の原因は Nokogiri が C のプリコンパイルに使っている rake-compiler-dock において glibc の最小サポートバージョンが引き上げられたことであるようだ。
なんで引き上げたのかは,どうも CentOS のサポート終了が原因だったようなのだが1,ええと,AlmaLinux 8 も Rocky Linux 8 も 2029 年まで生きてますよ?

rake-compiler-dock の History.md を見ると,この変更は 2024-12-13 の v1.6.0 で行われたようだ。

それはともかく,issue 主さんの記述を見ていて,私が本記事で書いたのとは別の対策があることを知った。

つまり,Gemfile に

Gemfile
gem "nokogiri", force_ruby_platform: true

のように書けばよい。
gem メソッドの force_ruby_platform なんてオプション知らなかったぞ。

このやり方であれば,他の gem のインストールに影響を与えることなく,nokogiri だけ自前コンパイルにできる。
これは .bundle/config で Bundler の動作を変える方法に比べて大きな利点だ。

しかし,短所もある。
Gemfile に書いちゃうわけなので,「本番サーバーでは自前コンパイルになってほしいが,手元の開発環境ではコンパイル済み版で」ということができない(しにくい)。

  1. 私の英語力では,そういう解釈で正しいのかよく分からん。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?