こんにちは、インフラ部のsue445です。
2025年4月16日(水)〜18日(金)に愛媛県松山市で開催されるRubyKaigi 2025に登壇します!
自分のトークについて
3日目の4月18日(金)に登壇予定です。
「Road to Go gem」というタイトルで、Rubyのnative extensionをGo言語で書きやすくした話をします。
RubyKaigiはコード自慢大会*1なのでここ最近趣味で作ってた https://github.com/ruby-go-gem/go-gem-wrapper やその周辺の話をします。
タイトルにGoが入っていますが実際にはC言語の話の方が多いかもしれません。
余談ですが僕の名前はGoです。
実際に採択されたProposal
実際に採択されたProposalはこちらになります。今後Proposalを出す時の参考にしてください。
このProposalの内容をベースに発表資料も作るので当日の僕のトークの予習資料としてもご利用ください。
Title
Road to Go gem
Agenda
Go talks about Ruby native extension gem with Go. (a.k.a. Go gem)
I created https://github.com/ruby-go-gem/go-gem-wrapper for Go gem.
This is a library to make it easier to create Go gem. (contains both Go module and Ruby gem)
I will talk the following regarding go-gem-wrapper and Go gem.
- Auto-generate (almost) all of Go's bindings from
ruby.h
. (about 1,100 functions) - Parse CRuby's
ruby.h
with Ruby - C lang's pointer difficulties from
ruby.h
parser's point of view - Run
go test
with CRuby - Pros/Cons of Go gem
- My bundler's patch for Go gem
Details
Goでnative extensionを作りやすくした話をします。
長いのでGoで作られたnative extensionのことを僕はGo gemと言っています。このプロポーザルでもそのように呼称します。
このトークは2024年9月に開催されたTokyuRuby会議15の発表の続きになります。 https://esa-pages.io/p/sharing/8985/posts/887/74fdd1ed44cec5284a40-slides.html#/18
Tokyuの時はWIPでしたが今回は完成してるので完成物(Go gemを作りやすくするためのライブラリとその周辺のエコシステム)の話をします。
これによりこれまでよりも少ないコード量でGo gemを作ることができます。
僕がbundlerに送ったパッチ(後述)がマージされると bundle gem --ext go
でGo gemのスケルトンが作れるようになるんですが、プロポーザル執筆時点ではまだマージされていないです。
コードだと下記の話が中心になります
- https://github.com/ruby-go-gem/go-gem-wrapper
- https://rubykaigi.org/2015/presentations/mmasaki/ の時には動いていたコードが、Goの内部仕様の変更により今はもう動かなくなっていた件の修正
- ruby.hをパースしてGoのbindingを自動生成し、Go module(Goのライブラリ)として利用できるようにしたライブラリ
- ruby.hに定義されている約1,100個の関数を実際に https://github.com/ruby-go-gem/go-gem-wrapper/blob/v0.6.0/ruby/function_ruby_3_4_generated.go のような形で自動生成している
- 他にもCRubyのenumやstructなどもGoで使えるようにbindingを自動生成している
- https://github.com/ruby-go-gem/go-gem-wrapper/tree/v0.6.0/_gem ( https://rubygems.org/gems/go_gem )
- extconf.rbにパッチを当ててGo gemをビルドするためのMakefileを作るためのgem
- Rust gemにおける https://rubygems.org/gems/rb_sys みたいなやつ
go test
を実行するためにはCRubyのRbConfig::CONFIG
をいい感じにGoに渡す必要があったのだが、結構コツがいるので https://github.com/ruby-go-gem/go-gem-wrapper/blob/v0.6.0/_gem/lib/go_gem/rake_task.rb のようなラッパも作った
- https://github.com/ruby-go-gem/ruby_header_parser
- go-gem-wrapperから切り出したruby.h専用のパーサー
- ctagsを使ってるので実はruby.h以外もいけるとは思うけど未検証
- bundlerの改良
- https://github.com/orgs/rubygems/discussions/8128
- bundlerでGo gem対応するためのproposal
- https://github.com/rubygems/rubygems/pull/8183
- 前述のproposalでhsbtさんからLGTMもらった後に実際にbundlerに送ったパッチ
- https://github.com/orgs/rubygems/discussions/8128
- https://github.com/sue445/funnel_http
- 実際に作ったGo gem
- 複数のHTTPリクエストをgoroutineの中から並列実行することで、ThreadやRactorなどのpure-Rubyな実装を寄せ付けないパフォーマンスを得ることができた
コード以外の部分のネタはこの辺があります。(探せばもっとあるかも)
ruby.h
をparseするために頑張ったこと- 既存のツールを検証した結果
- その結果なぜ自分でパーサーを書くことになったかの理由
- C言語のポインタを他言語で解釈する時の苦労話
- Go gemのメリット
- goroutineはRactorの約28倍速いw
- 現状Rubyで並行・並列処理を書く場合にはThreadやFiberやRactorを使うことになると思いますが、Go gemによりgoroutineという新しい選択肢ができました
- osyoyuさんも以前言ってたけどRubyを速くするためにRuby以外を書くことになった
- 現在の課題(Go gemの制限)
- Goの可変長引数をそのままCの可変長引数に渡せない件
- goroutineの中からCRubyの関数を呼ぶとSEGVになる件
- bundlerにFeature proposalやPRを投げた時の苦労点など
- 最初rubygemsのdiscussionに投稿した時にあまり反応がなかったのでruby-jp slackでhsbtさんに相談した
- bundlerはUbuntu/macOS/WindowsでそれぞれCIを実行しているのだが、特定のテストを実行しようとするとなぜかWindows Runnerだけでハングする事象が見つかって調査して直した件
- bundlerのWindowsのCIは通常時でも1.5時間くらいかかるので調査がむっちゃ大変だった
Pitch
Go gemに関する話は2015年のRubyKaigi( https://rubykaigi.org/2015/presentations/mmasaki/ )で話されたきりで、僕が知ってる範囲ではその後特に進展はなかったと思います。
2015年の発表当時だと bundle gem
した直後のスケルトンに色々手を加える必要があったので万人が手を出せるものではありませんでした。
そのため、ruby.hからGoのbindingを自動生成する仕組みを整えてbundlerに組み込めるレベルまで持っていくという一連のエコシステムを全て僕1人で作りました。
僕が取り組むまではbundlerにこの手のissueやproposalはなかったので、Go gemに取り組んでいるのは現在世界中でおそらく僕しかおらず、間違いなく僕にしかこの話はできないです。
ここ数年のRubyKaigiではRubyで書かれたコードのparserのトークが盛り上がっていますが、僕はもうちょっと低レイヤー寄りでCRubyのソースコードのparser枠として話をすることになると思いますw
bundle gem
に新しい言語を追加しようとしてる人はほとんどいないので、今後 bundle gem
に他の言語を追加したい人の手助けになると思っています。
補足
TitleとAbstractはサイトに公開されるものなので全て英語で記載してますが、Details(発表のテーマや流れ)とPitch(このCFPを採択すべき理由やアピール文)に関してはレビュアーしか見ないものなので日本語で記載しています。
【おまけ】過去のRubyKaigiで採択されたProposalの一覧
*1:諸説あります