はじめに
こんにちは。RubyでC拡張ライブラリを作らなければならないことになりそうです。
ここではその最初の一歩を踏み出します。
やってみよう
まずは hello world を作ります。Hello world をC言語で書くと
#include <stdio.h>
int main(void) {
printf("Hello world\n");
}
みたいな感じになりますね。これをRubyで再現するのを目標にします。
mkmfファイルを書く
Ruby の拡張ライブラリのための Makefile を作成するライブラリだそうです。extconf.rb
という名前にするようです。今回は以下のような感じにします。
require 'mkmf'
create_makefile("hello")
C言語のヘッダーファイルを作成する
ruby.h
というファイルをincludeするように設定します。
#include "ruby.h"
C言語のソースコードを書く
#include "hello.h"
#include <stdio.h>
void Init_hello(void)
{
printf("Hello world\n");
}
これらは同じディレクトリに配置します。
.
├── extconf.rb
├── hello.c
└── hello.h
作ったる
それでは実行していきます。
ruby extconf.rb
Makefileが作成されたはずです。
.
├── extconf.rb
├── hello.c
├── hello.h
└── Makefile
makeします
make
hello.o
と hello.so
が作成されました。
.
├── extconf.rb
├── hello.c
├── hello.h
├── hello.o
├── hello.so
└── Makefile
できた
この hello.so
が作成されたRuby拡張ライブラリということになります。irb
から呼び出してみましょう。
irb(main):001:0> irb
irb#1(main):001:0> require './hello.so'
Hello world
=> true
無事にHello worldが出力されました。成功です。
irb -r ./hello.so
でも実行できます。
Ruby拡張ライブラリを作るために必要な知識と資料
下記の資料が参考になりそうです。
- 公式資料 https://ruby-doc.org/core-3.0.0/doc/extension_ja_rdoc.html
- 英語の資料 https://github.com/silverhammermba/emberb
- mkmfリファレンス https://docs.ruby-lang.org/ja/latest/library/mkmf.html
C言語に触ったことはあるけど、RubyのC拡張はなかなか手が出ない人は次の記事も読んでみてください。
おまけ
せっかく初めての拡張ライブラリ(バイナリファイル)を作成したので、少し中身を観察してみましょう。
lddで共有ライブラリの依存関係をチェックする
ldd hello.so
linux-vdso.so.1 (0x00007ffc0eb97000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2404384000)
/lib64/ld-linux-x86-64.so.2 (0x00007f240459e000)
逆アセンブルしてみる
objdump -d -Sl hello.so
今回、逆アセンブルというものを初めてやりましたが、思ったよりも元のコードの情報が残っているのですね。
〜中略〜
0000000000001120 <Init_hello>:
Init_hello():
/home/kojix2/Ruby/tmp/hello/hello.c:5
#include "hello.h"
#include <stdio.h>
void Init_hello(void)
{
1120: f3 0f 1e fa endbr64
printf():
/usr/include/x86_64-linux-gnu/bits/stdio2.h:110
}
__fortify_function int
printf (const char *__restrict __fmt, ...)
{
return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
1124: 48 8d 3d d5 0e 00 00 lea 0xed5(%rip),%rdi # 2000 <_fini+0xed0>
112b: e9 20 ff ff ff jmpq 1050 <puts@plt>
シンボルをチェックする
nm -D hello.so
これは、ffiを使ってバインディグを作る時は、ときどき使いますね。一番最初に Init_helloが見えます。
0000000000001120 T Init_hello
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w __cxa_finalize@@GLIBC_2.2.5
w __gmon_start__
U puts@@GLIBC_2.2.5
この記事は以上です。