Skip to content

Instantly share code, notes, and snippets.

@wanabe
Last active October 13, 2020 03:16
Show Gist options
  • Select an option

  • Save wanabe/5ba643a3b0e40c05f8de255081e829f0 to your computer and use it in GitHub Desktop.

Select an option

Save wanabe/5ba643a3b0e40c05f8de255081e829f0 to your computer and use it in GitHub Desktop.
ruby が 0 という一文字を解釈する流れをわかりたい

この文章は

CRuby がプログラムをどう実行しているのかを自分がいまいち理解していないので、その理解のために書いていくものです。 実験的に、あっちこっちリンクで飛ぶように書きたいと思います。

はじまり

CRuby の実行ファイルである ruby(Windows であれば ruby.exe)は、Ruby スクリプトを解釈して実行します。 たとえば ruby -e 0 などとすると、0 という一文字の Ruby スクリプトだと解釈され、実行されます。画面に何も表示しないので本当かどうかよくわかりませんが、そうらしいです。

このとき内部では何が起きているのか、追ってみたいと思います。 読んでいくソースコードは ruby-2.7.1 としたいと思います。 https://github.com/ruby/ruby/tree/v2_7_1

main()

CRuby は C 言語で書かれており、実行されたときに最初に呼び出されるのは main() 関数です。 中身を抜粋します。

#ifdef RUBY_DEBUG_ENV
    ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
    setlocale(LC_CTYPE, "");
#endif

    ruby_sysinit(&argc, &argv);
    {
	RUBY_INIT_STACK;
	ruby_init();
	return ruby_run_node(ruby_options(argc, argv));
    }

マクロ定数 RUBY_DEBUG_ENV が定義されていたら環境変数 RUBY_DEBUG を取り出して ruby_set_debug_option() を呼び出す。 マクロ定数 HAVE_LOCALE_H が定義されていたら、つまり locale.h が読み込まれていたら setlocale() で LC_TYPE をクリアする。 ここまではあまり本質的ではない前処理です。

これ以降の処理を箇条書きします。

  • ruby_sysinit() を呼び出す。
  • RUBY_INIT_STACK マクロを展開する。
  • ruby_init() を呼び出す。
  • ruby_run_node() を呼び出して返り値を返す。
    • このとき引数に ruby_options() の返り値を渡す。

たったこれだけでした。簡単ですね……というわけにはいきません。 要素数は少ないですがそれぞれの要素が何を表す何をするものなのか、これだけだとまったくわかりません。

個別に見ていきます。

RUBY_DEBUG_ENV

このマクロが設定されているとき、起動時に ruby_set_debug_option() を呼び出します。 それ以外にこのマクロを参照している箇所がないので、この呼び出しの有無を制御するためだけのもののようです。

ifdef HAVE_***_H をなぜ「***.h が読み込まれていたら」と読み下すのか?

これは CRuby に限らず、C 言語のヘッダーファイル、とくに *nix とか POSIX とか言われる界隈で見られる慣習およびテクニックのようです。 初出がどこなのかは私は知りませんが、ヘッダーファイル全体を

/* locale.h */
#ifndef HAVE_LOCALE_H
#define HAVE_LOCALE_H
...(中略)..
#endif /* HAVE_LOCALE_H */
[EOF]

のような形で #ifndef ... #endif でくるんでやることで、

  • 読み込まれる前 -> HAVE_LOCALE_H 未定義
  • 初回読み込み -> HAVE_LOCALE_H 定義しつつ、ヘッダーファイルの内容を展開する
  • 二回目以降の読み込み -> HAVE_LOCALE_H 定義済みなのでなにもしない

というようにすることがよくあります。これにより「多重読み込み防止」「ヘッダーをすでに読み込んだかの判断が可能になる」というものです。

TODO

まだ書けていません。すみません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment