いけむランド

はてダからやってきました

cygwin setup で最新の ruby をインストールできるようにした話

長い間 cygwin 側の ruby のパッケージメンテナが不在だったが、EOL で放置されてしまっている状態は rubyist としては寂しいと感じ、一念発起して adopt *1 することした。*2

まず、先に rubygems を更新することにした。理由は以下の記事に書いてるとおり。

fd0.hatenablog.jp

こちらはあっさりアップデートが完了できた。メンテナ向け ML でのやりとりは以下のとおり。

www.mail-archive.com

アップデートすることで自分の環境では不具合っぽい現象を踏んでしまったが、似たような issue が挙がっていたため、わかってることをコメントしておいた。*3

github.com

次に本丸の ruby の更新に着手した。ML でのやりとりは以下のとおり。

www.mail-archive.com

cygwin 側でメンテナンスしている ruby (と ruby で書かれたサブパッケージ群) は soversion によるパッケージ分け *4 をしていなかったため、何もせずに ruby-3.2.2 を current にすると、ruby-2.6.4 の cygruby260.dll に依存しているものが軒並み動かなくなるということを教えてもらった。*5

対応策として perl でやっている依存管理の方法を教えてもらった。配布サーバの依存情報 setup.ini *6provides というヘッダがあり、そこに soversion 付きのラベル ruby_xy (x がメジャーバージョン、y がマイナーバージョンになる。今回のアップデートで生成されるラベルは ruby_32 となる) を設定したら、それ以外の cygrubyxy0.dll に依存しているものは新たにインストールできなくなるため、それを適用するということになった。

本当は他にも

  • ruby-2.6.4 に ruby_PROVIDES を追加して再パッケージする。
  • ruby に依存したパッケージの depends (上述の provides に対応するヘッダ) に ruby_xy を追加する。

など、手順がたくさんあるなあと思っていたが、メンテナのリードの方が直接 setup.ini を書き換えるという強権発動? で、半分以上の作業は対応不要になった。

ということで ruby-3.2.2 のリリース以外にやるべきことは cygport の修正だけとなった。ちなみに cygport の修正は ruby-3.2.2 のリリース後に ruby に依存したパッケージを再ビルドに着手するまでに対応すれば良かったが、patch を書きたかったら書いてもいいよみたいなことを言われた & perl でやっている処理と同じようにすれば良さそうだったため、サラッと書いてみた。

cygwin.com

これらの修正は ruby に依存したパッケージのビルド時にどの ruby の soversion に依存しているかを検出する処理であり、概要は以下のとおり。

  • vendor_ruby 配下に ${major_version}.${minor_version} というディレクトリがつくられるため、そこから ruby_xy をつくる。
  • バイナリの objdump の結果から cygrubyxy0.dll が見つかったら、そこから ruby_xy をつくる。 *7

これが merge されて cygport-0.36.3 がリリースされた。

www.mail-archive.com

そして ruby-3.2.2 のリリースをしようと、ジョブサーバからデプロイをすると、setup.ini を再生成するスクリプトが実行されるのだが、しばらくするとエラーになってしまう。*8

ERROR: package 'ruby-caca' version '0.99.beta19-4' depends: 'ruby_23', but nothing satisfies that
(以下略)

古い ruby に依存しているものに ruby-2.3.x が必要であるというラベル ruby_23setup.ini にリードの方が付与していたが、既に ruby-2.3.x をインストールする方法がないため、依存解決ができないから setup.ini を更新できない & ruby-3.2.2 のデプロイもされないという状態になった。

この状況を ML で質問すると、再びリードの方が対応してくれた。ドキュメントには明言されていないが、対応前後の setup.ini の差分を見ると、depends2 ヘッダに ruby_23 が移動していたため、おそらくこのヘッダが「依存はあるけど無視しても良い」というものなのだろう。

というわけで何とかリリースをしたが、ちょっとしてやらかしが発覚してしまう。

www.mail-archive.com

gem install して ~/bin にインストールされたラッパースクリプト内の ruby のパスが間違ってて、動かないという問題。

冷や汗を流しながら、必死に調べると、原因は以前からあるパッチ 2.0.0-cygwin-configure.patch の適用を忘れていて *9、それによって rbconfig の中身が異なってしまっているせいだった。

詳細を説明すると LIBRUBY_RELATIVE が true の場合は生成したラッパースクリプトと同じディレクトリに ruby インタプリタがあるというラッパースクリプトを生成してしまう。false の場合は /usr/bin/ruby になり、きちんと動く。

github.com

というわけでそれを適用して、再度リリースした。

cygwin.com

再リリースしてからは追加の問い合わせメールは流れていないが、使用者があまりいないからなのかは正直わからない。*10

これから ruby_26 に依存しているパッケージの adopt をちょっとずつしていこうかと思っているが、個人的には gem は別に cygwin 側から提供しなくても、各自で gem install すればいいんじゃないかという気がする。一人の人間がそれら全部を最新に追従させるのは困難、というかフルタイムコミットでも無理なのでは? と密かに思ってる。

*1:どうも cygwin ではメンテナ不在のパッケージのメンテナンスを引き受けることを adopt と表現するらしい。一般的にそういうのかはわからない。 https://cygwin.com/acronyms/#ITA

*2:読み間違える人はいないと思いますが念のために言っておくと ruby のコミッタになったわけではないです。

*3:一つ前の 3.0.4 では発生していなかったため、発見時はパッケージスクリプトのミスかわからなくて、かなり焦った。

*4:cygwin 側で配布している python はパッケージ名の末尾に soversion 由来の数字をつけることで別のパッケージとして、個別にインストールできるようにしている。他のディストリビューションでは FreeBSD がこの方式を採用している。 FreeBSD Ports Search

*5:インストールはできるけど、実行時に DLL が見つからないというエラーになる。例 : windows - dll file missing when debugging for android in Qt - Stack Overflow

*6:setup.ini documentation

*7:リリース後に気づいたが、これだと ruby 自身も ruby への依存を持ってしまうため、厳密には自身を除外する if 文が必要と思われる。あとで修正依頼を出す予定。

*8:非同期に実行するため、エラーはメールで届く。

*9:作業初期にそのままだと適用できないからとあとでやろうと外してしまっていたことを完全に忘れていた

*10:ダウンロード数を知る方法がないというのもある。