Edited at
移行Day 19

AdventCalendar Day19 [超Ruby入門]


はじめに

本記事は、超Ruby入門19日目の記事です。

コメント頂ける方は、ガイドラインを読んで頂けると幸いです。


RHCとは

Ruby Hack Challenge(RHC)とは、Rubyコミッターが講師になってRubyの内部を触るという、いい感じのイベントです。

rubyhackchallenge


本題

RHCの演習を解説していきます。

MRI ソースコードの構造を参考にビルド等を行って下さい。


演習:バージョン表記の修正(改造)


まずは、ruby -v(もしくは ./miniruby -v)を実行したときに、自分の Ruby だとわかるように、何か表示を変えてみましょう。


これは、簡単ですね。

fflush(stdout);の前に、printf()で表示させるだけです。


workdir/ruby/version.c

void

ruby_show_version(void)
{
if (MJIT_OPTS_ON) {
PRINT(description_with_jit);
}
else {
PRINT(description);
}
#ifdef RUBY_LAST_COMMIT_TITLE
fputs("last_commit=" RUBY_LAST_COMMIT_TITLE, stdout);
#endif
#ifdef HAVE_MALLOC_CONF
if (malloc_conf) printf("malloc_conf=%s\n", malloc_conf);
#endif
printf("imaharu\n");
fflush(stdout);
}


最後に printf(...) を挟むだけではなく、ruby ... と書かれた行を変更しても面白いかもしれませんね。perl と出力してみるとか。


ruby 2.6.0dev ....


Python 2.6.0dev ....

さて、Pythonと出力させるためにコードを追っていきましょう。

fflush(stdout);に注目します。fflushは、バッファに格納されているデータを吐き出すので、どこでデータが出力されているはずです。

怪しいのは、どう見てもPRINTですね。


workdir/ruby/version.c

    if (MJIT_OPTS_ON) {

PRINT(description_with_jit);
}
else {
PRINT(description);
}

PRINTという文字をファイル内検索すると、関数が定義されていることが確認できました。


workdir/ruby/version.c

#define PRINT(type) puts(ruby_##type)

#define MKSTR(type) rb_obj_freeze(rb_usascii_str_new_static(ruby_##type, sizeof(ruby_##type)-1))
#define MKINT(name) INT2FIX(ruby_##name)

PRINT(type)の引数には、descriptionが与えられています。

descriptionは、RUBY_DESCRIPTION_WITHで生成されているようです。


workdir/ruby/version.c

const char ruby_description[] = RUBY_DESCRIPTION_WITH("");

static const char ruby_description_with_jit[] = RUBY_DESCRIPTION_WITH(" +JIT");

RUBY_DESCRIPTION_WITHは、version.cには、定義されていないので

includeされているファイルを確認して見ましょう。


workdir/ruby/version.c

#include "ruby/ruby.h"

#include "version.h"
#include "vm_core.h"
#include "mjit.h"
#include <stdio.h>

#include "version.h"が、いかにもな雰囲気を醸し出していますね。


workdir/ruby/version.h

# define RUBY_DESCRIPTION_WITH(opt) \

"ruby "RUBY_VERSION \
RUBY_PATCHLEVEL_STR \
" ("RUBY_RELEASE_DATE \
RUBY_REVISION_STR")"opt" " \
"["RUBY_PLATFORM"]"

"ruby "RUBY_VERSION


"Python "RUBY_VERSION

該当箇所を上記のように変更して、確認して見ましょう。

$pwd 

> /workdir/build
$ make miniruby
$./miniruby -v
Python 2.6.0dev .....

以上で演習:バージョン表記の修正(改造)の解説は終わりです。


深めたい人

興味のある人は、演習:メソッドの追加に挑戦してみましょう。