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
sylph01
March 09, 2025
Programming
300
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
230
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
280
The Definitive? Guide To Locally Organizing RubyKaigi
sylph01
9
3.9k
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
960
"Actual" Security in Microcontroller Ruby!?
sylph01
0
240
Everyone Now Understands AuthZ/AuthN and Encryption Perfectly and I'm Gonna Lose My Job
sylph01
1
130
Other Decks in Programming
See All in Programming
Webフレームワークの ベンチマークについて
yusukebe
0
200
OSINT for SRE: 学術論文とポストモーテムから探る システム障害の共通パターン / SRE NEXT 2026
tomoyk
1
3.4k
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
610
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
360
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
120
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
200
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
570
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
230
act1-costs.pdf
sumedhbala
0
210
【やさしく解説 設計編 #1】「ドメイン駆動」と「実装駆動」ってなに? 〜設計の考え方を、たとえ話で学ぼう〜
panda728
PRO
1
110
1B+ /day規模のログを管理する技術
broadleaf
0
130
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.4k
Featured
See All Featured
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
260
Six Lessons from altMBA
skipperchong
29
4.3k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
470
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
190
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.6k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
190
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.7k
Building Applications with DynamoDB
mza
96
7.1k
We Are The Robots
honzajavorek
0
270
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