Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Introduction to C Extensions
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
sylph01
March 09, 2025
Programming
310
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Introduction to C Extensions
@ kyoto.rb 2025/3/9
sylph01
March 09, 2025
More Decks by sylph01
See All by sylph01
人命を救う技術としてのEnd-to-End暗号化とMessaging Layer Security
sylph01
3
240
Updates on MLS on Ruby (and maybe more)
sylph01
1
290
End-to-End Encryption Saves Lives. You Can Start Saving Lives With Ruby, Too (RubyConf Taiwan 2025 ver.)
sylph01
1
170
PicoRuby's Networking is Incomplete
sylph01
1
300
The Definitive? Guide To Locally Organizing RubyKaigi
sylph01
9
4k
End-to-End Encryption Saves Lives. You Can Start Saving Lives With Ruby, Too
sylph01
1
220
End-to-End Encryption Saves Lives. You Can Start Saving Lives With Ruby, Too (JP subtitles)
sylph01
2
990
"Actual" Security in Microcontroller Ruby!?
sylph01
0
250
Everyone Now Understands AuthZ/AuthN and Encryption Perfectly and I'm Gonna Lose My Job
sylph01
1
140
Other Decks in Programming
See All in Programming
Lean は証明の正しさを確認するためだけのツールって思ってませんか?
inoueasei
1
150
AWS CDK を「作」ってみた 〜フルスクラッチで見えた CDK の裏側〜 / aws-cdk-from-scratch
gotok365
3
2.8k
AIが無かった頃の素敵な出会いの話
codmoninc
1
390
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
220
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.7k
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
770
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
540
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.7k
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
480
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
730
the container ship “Apple Silicon”@WWDC26 Recap -Japan-\(region).swift
shingangan
0
110
Go 1.27 における memory allocation の高速化
andpad
0
110
Featured
See All Featured
Crafting Experiences
bethany
1
240
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
440
Balancing Empowerment & Direction
lara
6
1.2k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.5k
Become a Pro
speakerdeck
PRO
31
6.2k
Rails Girls Zürich Keynote
gr2m
96
14k
Facilitating Awesome Meetings
lara
57
7.1k
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
240
Believing is Seeing
oripsolob
1
180
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Transcript
Introduction to C Extensions Ryo Kajiwara (sylph01), 2025/3/9 @ kyoto.rb
1
RubyKaigi, more like CKaigi, huh? よく冗談めかして言われますね 2
C 拡張って何 C 言語でRuby の機能を書くこと gem の形で使うことが多い C やアセンブリで書いたほうが速い部分をC で書く
実はJIT のおかげで必ずしもC だから速いというわけでもない C 以外の言語の入り口になることもある そういえば今年Go gem の話がありますね? 3
現代RubyKaigi ではもはやC 拡張の話は 当たり前のこととして通過される RubyKaigi のトークには新規性が必要(なことが多い) Ruby Core としてはもはや当たり前のもの C
で書かれたライブラリのラッパーだけでは新規性がない とはいえスルーするにはあまりにも不親切。なので今回できる限りの解 説を試みる。全部は 私もわからないので 解説しきれません。 4
見るべき2 大ドキュメント ruby/ruby のdoc/extension.rdoc 日本語がある(リンクは日本語のほう) The Definitive Guide to Ruby's
C API 5
実際に自分が手を入れた/ ているコー ドがこちら https:/ /github.com/sylph01/openssl/blob/hpke/ext/openssl/ossl_hpke _ctx.c https:/ /github.com/sylph01/openssl/blob/hpke/ext/openssl/ossl_ hpke_ctx.h https:/
/github.com/sylph01/openssl/blob/hpke/ext/openssl/ossl.c から Init_ossl_hpke_ctx() が呼ばれるのがエントリーポイ ント 6
クラス/ モジュールの定義 void Init_ossl_hpke_ctx(void) { mHPKE = rb_define_module_under(mOSSL, "HPKE"); cContext
= rb_define_class_under(mHPKE, "Context", rb_cObject); cSenderContext = rb_define_class_under(cContext, "Sender", cContext); cReceiverContext = rb_define_class_under(cContext, "Receiver", cContext); eHPKEError = rb_define_class_under(mHPKE, "HPKEError", eOSSLError); ... class OpenSSL::HPKE::Context class OpenSSL::HPKE::Context::Sender class OpenSSL::HPKE::Context::Receiver class OpenSSL::HPKE::Error 7
メソッドの定義 rb_define_method(cSenderContext, "initialize", ossl_hpke_ctx_new_sender, 2); (1) 定義したいクラス、(2) メソッド名、(3) 実装を示す関数ポインタ、(4) 引数の個数
以下に相当 class OpenSSL::HPKE::Context::Sender def initialize(arg1, arg2) end 8
メソッドの定義 VALUE ossl_hpke_ctx_new_sender(VALUE self, VALUE mode, VALUE suite) { ...
C の世界ではRuby のオブジェクトは全部 VALUE 自身がどんな型であるかを知っているデータ(へのポインタ) (1) self 、(2) 以降は rb_define_method で指定した引数の数だけ VALUE が続く return で返す VALUE がRuby の世界で返る値 9
メソッドの定義 おまけ: モジュール関数の場合は rb_define_module_function rb_define_module_function(mHPKE, "keygen", ossl_hpke_keygen, 3); おまけ2: mruby/c
ではどうするの?→るびま0064 号のRubyKaigi 2024 の トーク解説記事 10
attributes // attr_readers for suite values rb_define_attr(cContext, "kem_id", 1, 0);
rb_define_attr(cContext, "kdf_id", 1, 0); rb_define_attr(cContext, "aead_id", 1, 0); https:/ /docs.ruby-lang.org/ja/latest/function/rb_define_attr.html 第3 引数はread 、第4 引数はwrite 11
インスタンス変数 rb_iv_set(self, "@kem_id", kem_id); kem_id = rb_iv_get(suite, "@kem_id"); get するときは
VALUE が返ってくるので、Ruby の世界のinteger をC で使 う場合は NUM2INT(kem_id) みたいな形で変換する。 12
定数の呼び出し https:/ /docs.ruby-lang.org/ja/latest/function/rb_const_get_at.html による と VALUE rb_const_get_at(VALUE klass, ID name)
。 ID → rb_intern で名前との対応関係が得られる。 mode_table = rb_const_get_at(cContext, rb_intern("MODES")); 13
Ruby の世界の関数を呼び出す mode_id = rb_funcall(mode_table, rb_intern("[]"), 1, mode); ↓ mode_id
= MODES[mode] rb_p(rb_funcall(rbstr, rb_intern("unpack1"), 1, rb_str_new_cstr("H*"))); ↓ p(str.unpack1("H*")) 14
C の構造体をRuby で包む static void ossl_hpke_ctx_free(void *ptr) { OSSL_HPKE_CTX_free(ptr); }
const rb_data_type_t ossl_hpke_ctx_type = { "OpenSSL/HPKE_CTX", { 0, ossl_hpke_ctx_free, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY }; 15
C の構造体をRuby で包む static VALUE hpke_ctx_new0(VALUE arg){ OSSL_HPKE_CTX *ctx =
(OSSL_HPKE_CTX *)arg; VALUE obj; obj = rb_obj_alloc(cContext); RTYPEDDATA_DATA(obj) = ctx; return obj; } VALUE ossl_hpke_ctx_new(OSSL_HPKE_CTX *ctx){ VALUE obj; int status; obj = rb_protect(hpke_ctx_new0, (VALUE)ctx, &status); if (status) { OSSL_HPKE_CTX_free(ctx); rb_jump_tag(status); } return obj; 16
C の構造体をRuby で包む static VALUE ossl_hpke_ctx_alloc(VALUE klass) { return TypedData_Wrap_Struct(klass,
&ossl_hpke_ctx_type, NULL); } void Init_ossl_hpke_ctx(void) { mHPKE = rb_define_module_under(mOSSL, "HPKE"); cContext = rb_define_class_under(mHPKE, "Context", rb_cObject); ... rb_define_alloc_func(cContext, ossl_hpke_ctx_alloc); } 17
C 拡張ってどうやってビルドするの? https:/ /docs.ruby-lang.org/ja/latest/library/mkmf.html Makefile を生成するためのライブラリ。 extconf.rb からmkmf をrequire してMakefile
が作られてshared object が作ら れる。 皆さんももしかしたら apt-get し足りない何かがあったときに extconf.rb がfailed になってるのを見たことあるかもしれない。 18
おまけ: Copilot に作らせてみた だいたい https:/ /github.com/tilo/gem_with_c_extension と近い内容のも のが出てきたが、Mac でビルドできなかった。shared object
( .so ) ファ イルが作られなかった 19
ext/my_c_extension/extconf.rb require 'mkmf' create_makefile('my_c_extension/my_c_extension') 20
ext/my_c_extension/my_c_extension.c #include "ruby.h" VALUE rb_mMyCExtension; VALUE hello_world(VALUE self) { return
rb_str_new_cstr("Hello, world!"); } void Init_my_c_extension() { rb_mMyCExtension = rb_define_module("MyCExtension"); rb_define_method(rb_mMyCExtension, "hello_world", hello_world, 0); } 21
gemspec Gem::Specification.new do |spec| # ... other configurations ... spec.extensions
= ['ext/my_c_extension/extconf.rb'] spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").select do |f| f.match(%r{^(ext|lib)/}) || f == 'my_c_extension.gemspec' end end # ... other configurations ... end 22
Ruby ラッパー require 'my_c_extension/my_c_extension' module MyCExtension def self.hello MyCExtension.hello_world end
end 23