見逃していました.
レビューはコミットされた後で,ってのはなかなか意外.

(2012/06/14 11:22), yugui wrote:
> yugui	2012-06-14 11:22:08 +0900 (Thu, 14 Jun 2012)
> 
>   New Revision: 36079
> 
>   http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=36079
> 
>   Log:
>     Embedding CRuby interpreter without internal headers has been difficult
>     for few years because:
>     * NODE is no longer accessible.
>     * rb_iseq_eval_main crashes without preparing with rb_thread_t.
>     * some existing APIs calls exit(3) without giving the opportunity to
>       finalize or handle errors to the client.
>     * No general-purpose function to compile a source to an iseq are
>       published in the public headers.
>     
>     This commit solves the problems.
>     
>     * include/ruby/ruby.h: Grouped APIs for embedding CRuby interpreter.
>       (ruby_setup, ruby_compile_main_from_file,
>       ruby_compile_main_from_string, ruby_eval_main,
>       ruby_set_script_name): new APIs to embed CRuby.
>       (ruby_opaque_t) Opaque pointer to an internal data, to NODE or iseq
>       in particular.
>     
>     * eval.c (ruby_setup): Similar to ruby_init but returns an error code
>       instead of exit(3) on error.
>       (ruby_eval_main): Similar to ruby_exec_node but returns the
>       evaluation result.
>       (ruby_eval_main_internal): renamed from ruby_exec_internal.
>     
>     * ruby.c (toplevel_context): new helper function.
>       (PREPARE_EVAL_MAIN): moved.
>       (process_options): refactored with new functions.
>       (parse_and_compile_main) new helper funciton.
>       (ruby_compile_main_from_file, ruby_compile_main_from_string) new API
>       (ruby_set_script_name): new API.
> 
>   Modified files:
>     trunk/ChangeLog
>     trunk/eval.c
>     trunk/include/ruby/intern.h
>     trunk/include/ruby/ruby.h
>     trunk/ruby.c

 ChangeLog よりもコミットログが長いのは,そういうもんでしょうか.同じ内
容を書いておいた方が良いんじゃないかと.


> Index: include/ruby/ruby.h
> ===================================================================
> --- include/ruby/ruby.h	(revision 36078)
> +++ include/ruby/ruby.h	(revision 36079)
...
> +/**
> + * @defgroup embed CRuby Embedding APIs
> + * CRuby interpreter APIs. These are APIs to embed MRI interpreter into your
> + * program.
> + * These functions are not a part of Ruby extention library API.
> + * Extension libraries of Ruby should not depend on these functions.
> + * @{
> + */
> +
> +/*! Opaque pointer to an inner data structure.
> + *
> + * You do not have to know what the actual data type this pointer points.
> + * It often changes for internal improvements.
> + */
> +typedef void *ruby_opaque_t;

そのまま void * じゃ駄目なんでしたっけ? 今,void * と混ざっているよう
ですが.

> +
> +/*! @deprecated You no longer need to use this macro. */ 
> +#if (defined(__APPLE__) || defined(__NeXT__)) && defined(__MACH__)
> +#define RUBY_GLOBAL_SETUP /* use linker option to link startup code with ObjC support */
> +#else
> +#define RUBY_GLOBAL_SETUP
> +#endif
> +
> +/** @defgroup ruby1 ruby(1) implementation
> + * A part of the implementation of ruby(1) command.
> + * Other programs that embed Ruby interpreter do not always need to use these
> + * functions.
> + * @{
> + */

 この defgroup の範囲がわからないのですが,RUBY_INIT_STACK
か,ruby_init_stack() はスタックの範囲(マシンスタックの GC mark の範
囲)を決めるのに必須になりますので, do not always ではないんじゃないかと.

 構成的には,

- 必須な項目
- optional な項目

の順番に並んでいた方がいいかと思います.が,そういうのはヘッダじゃなくて
なんか README.embedded みたいなのを書くのが筋だろうか.

> +void ruby_sysinit(int *argc, char ***argv);
> +void ruby_init(void);
> +ruby_opaque_t ruby_options(int argc, char** argv);
> +int ruby_executable_node(ruby_opaque_t n, int *status);
> +int ruby_run_node(ruby_opaque_t n);
> +
> +/* version.c */
> +void ruby_show_version(void);
> +void ruby_show_copyright(void);

 version とかって,これは埋め込みのためなんだろうか.

> +/*! A convenience macro to call ruby_init_stack(). Must be placed just after
> + *  variable declarations */
> +#define RUBY_INIT_STACK \
> +    VALUE variable_in_this_stack_frame; \
> +    ruby_init_stack(&variable_in_this_stack_frame);
> +/*! @} */
> +
> +#ifdef __ia64
> +void ruby_init_stack(volatile VALUE*, void*);
> +#define ruby_init_stack(addr) ruby_init_stack((addr), rb_ia64_bsp())
> +#else
> +void ruby_init_stack(volatile VALUE*);
> +#endif
> +#define Init_stack(addr) ruby_init_stack(addr)
> +
> +int ruby_setup(void);
> +int ruby_cleanup(volatile int);
> +
> +void ruby_finalize(void);

 ruby_finalize と ruby_cleanup って何が違うんだっけ....

> +NORETURN(void ruby_stop(int));
> +
> +void ruby_set_stack_size(size_t);

 これはなんでしょう.実装が見つからないようですが.

> +int ruby_stack_check(void);

 これ,公開する必要あるんだっけ.

> +size_t ruby_stack_length(VALUE**);

 同上.

 そもそも intern.h にあったんですね.うーん,これらを使うシチュエーショ
ンってあるでしょうか.

> +ruby_opaque_t ruby_compile_main_from_file(VALUE fname, const char* path, VALUE* error);
> +ruby_opaque_t ruby_compile_main_from_string(VALUE fname, VALUE string, VALUE* error);

 コンパイルって要りますかね.eval だけじゃ駄目なんでしたっけ.つまり,
ファイル名,もしくは文字列渡して実行するインターフェースだけだと不十分?

 ファイル名を渡すなら,ruby_options でファイル名渡せば main で実行され
ますんで,文字列で実行する版だけがあればよい?


> +int ruby_exec_node(ruby_opaque_t n);
> +int ruby_eval_main(ruby_opaque_t n, VALUE *result);

 eval_main というのが適切か自信がありません.eval_in_main_context とか
だと冗長でしょうか.

> +void ruby_script(const char* name);
> +void ruby_set_script_name(VALUE name);
> +
> +void ruby_prog_init(void);
> +void ruby_set_argv(int, char**);
> +void *ruby_process_options(int, char**);
> +void ruby_init_loadpath(void);
> +void ruby_incpush(const char*);
> +void ruby_sig_finalize(void);

 最後のほうはすみません,よくわかりません.

> Index: eval.c
> ===================================================================
> --- eval.c	(revision 36078)
> +++ eval.c	(revision 36079)
...
> +/* Initializes the Ruby VM and builtin libraries.
> + * @retval 0 if succeeded.
> + * @retval non-zero an error occured.
> + */
> +int
> +ruby_setup(void)
>  {

 0 が成功ってのは,ほかもありましたっけ.

> Index: ruby.c
> ===================================================================
> --- ruby.c	(revision 36078)
> +++ ruby.c	(revision 36079)
> @@ -496,6 +496,26 @@
>      th->base_block = prev_base_block;
>  }
>  
> +static rb_env_t*
> +toplevel_context(void)
> +{
> +    rb_env_t *env;
> +    VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
> +    rb_binding_t *bind;
> +
> +    GetBindingPtr(toplevel_binding, bind);
> +    GetEnvPtr(bind->env, env);
> +    return env;
> +}

 context と env は違いますので,この関数名はまずい.context はいろんな
意味で使われるので,指定しない context はわかりづらい,という感じで
す.cont.c だと rb_context_t なんてのがあるけど.

 toplevel_env() でいいんじゃないかな.

-- 
// SASADA Koichi at atdot dot net