ruby-dev (Japanese) list archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-dev:45745] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
       [not found] <20120614022221.A45366858E@sakura.atdot.net>
@ 2012-06-14 23:26 ` SASADA Koichi
  2012-06-15  7:30   ` [ruby-dev:45747] " Yugui
  0 siblings, 1 reply; 19+ messages in thread
From: SASADA Koichi @ 2012-06-14 23:26 UTC (permalink / raw
  To: ruby developers list

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

(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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45747] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-14 23:26 ` [ruby-dev:45745] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult SASADA Koichi
@ 2012-06-15  7:30   ` Yugui
  2012-06-15  8:29     ` [ruby-dev:45748] " SASADA Koichi
                       ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Yugui @ 2012-06-15  7:30 UTC (permalink / raw
  To: ruby developers list

2012/6/15 SASADA Koichi <ko1@atdot•net>:
> 見逃していました.
> レビューはコミットされた後で,ってのはなかなか意外.
>
> (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 * と混ざっているよう
> ですが.

何で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 ではないんじゃないかと.

そのグループはruby_init_stackの直前で終わってます。

>
>  構成的には,
>
> - 必須な項目
> - 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 とかって,これは埋め込みのためなんだろうか.

Matzのcopyrightを表示したいというニーズはどこかにあるんじゃないですかね。
少なくともextのためのものではないので。

extのためのものでないAPIを一まとめにしてみました。

>
>> +/*! 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 にあったんですね.うーん,これらを使うシチュエーショ
> ンってあるでしょうか.

ですです。使う必要が無いなら隠しても良いですが、互換性への配慮は必要ですね。
とりあえずdeprecated attributeでも付けてみますか?

>
>> +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 が成功ってのは,ほかもありましたっけ.

この辺の関数は全部exit(3)に渡す前提なので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() でいいんじゃないかな.

I agree


>
> --
> // SASADA Koichi at atdot dot net
>



-- 
Yuki Sonoda (Yugui)
yugui@yugui•jp
http://yugui.jp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45748] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15  7:30   ` [ruby-dev:45747] " Yugui
@ 2012-06-15  8:29     ` SASADA Koichi
  2012-06-15  9:29       ` [ruby-dev:45749] " U.Nakamura
  2012-06-15 13:02       ` [ruby-dev:45751] " Yugui
  2012-06-15 22:01     ` [ruby-dev:45755] " Nobuyoshi Nakada
  2012-06-18 19:49     ` [ruby-dev:45762] " SASADA Koichi
  2 siblings, 2 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-15  8:29 UTC (permalink / raw
  To: ruby developers list

 ささだです.

(2012/06/15 16:30), Yugui wrote:
>> ...
>>> +/**
>>> + * @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 * と混ざっているよう
>> ですが.
> 
> 何でvoid*なのか一瞬考えたことがあったので、明示するのは悪くないと思います。
> 混ざってるならそれは見落としですね。

 個人的には,opaque ってなんじゃらと混乱しましたので,よくわからんポイ
ンタだとわかる void * のほうが好きなのですが.hoge_opaque_t ってのは,よ
く知られた表現なんですかね?

 この辺は,bikeshed になるでしょうか.どうしたもんですかね.


>>  構成的には,
>>
>> - 必須な項目
>> - 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 とかって,これは埋め込みのためなんだろうか.
> 
> Matzのcopyrightを表示したいというニーズはどこかにあるんじゃないですかね。
> 少なくともextのためのものではないので。
> 
> extのためのものでないAPIを一まとめにしてみました。

 了解です.


> ですです。使う必要が無いなら隠しても良いですが、互換性への配慮は必要ですね。
> とりあえずdeprecated attributeでも付けてみますか?

 この辺は別件として整理するべきでしょうか.


>>> +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 だけじゃ駄目なんでしたっけ.つまり,
>> ファイル名,もしくは文字列渡して実行するインターフェースだけだと不十分?

 この点についてはどうでしょうか.

 IRCNet#ruby-ja で,

> 16:55 yugui      > 同じ式を繰り返し評価したいニーズは埋め込みでは結構
あるので

ということで,使い回したい,ということかと思うのですが,

(1) 使い回すならメソッドとして定義したほうがよさそう
(2) コンパイルするコストは本当に問題か?

というのが気になります.これが無くなると,iseq を見せなくてよさそうだか
ら(opaque ってなんだろうと思わなくて済むので),評価までやっちゃったほ
うがいいじゃないかな,と思っています.


>>  ファイル名を渡すなら,ruby_options でファイル名渡せば main で実行され
>> ますんで,文字列で実行する版だけがあればよい?
> 
> オプション解析がまったく余分です。

 余分であって,出来ないわけじゃないですよね.困る場合はあるでしょう
か.1つ思いついたのは,ファイル名を正しくクオートした文字列として渡さな
いといけないのが困るかな,という点でした.

 現状,Ruby への起動インターフェースをまとめたもの,ということかと思っ
ています.


>>> +int ruby_exec_node(ruby_opaque_t n);
>>> +int ruby_eval_main(ruby_opaque_t n, VALUE *result);
>>
>>  eval_main というのが適切か自信がありません.eval_in_main_context とか
>> だと冗長でしょうか.
> 
> それでもいいかもしれません。

 あと,Kernel.eval というのは文字列をとるので,iseq を受け取るインター
フェースは混乱しそうな気がします(なので,上で述べた文字列を受け取り評価
までするほうがいいんじゃないかな,と思っています).


>>> 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 が成功ってのは,ほかもありましたっけ.
> 
> この辺の関数は全部exit(3)に渡す前提なので0が成功ですね。

 了解です.

 気になったのが,内部で使う分には「気を付けよう」で済むのが,外部へ出す
となると,0失敗,1成功,のほうがわかりやすいかな,と思ったのでした.

 返値を ruby_exit_code_t という型にすると,ちょっとわかりやすくなるかも
しれませんね.


-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45749] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15  8:29     ` [ruby-dev:45748] " SASADA Koichi
@ 2012-06-15  9:29       ` U.Nakamura
  2012-06-15 12:41         ` [ruby-dev:45750] " Yugui
  2012-06-15 13:02       ` [ruby-dev:45751] " Yugui
  1 sibling, 1 reply; 19+ messages in thread
From: U.Nakamura @ 2012-06-15  9:29 UTC (permalink / raw
  To: ruby developers list

こんにちは、なかむら(う)です。

In message "[ruby-dev:45748] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult"
    on Jun.15,2012 17:29:57, <ko1@atdot•net> wrote:
> > 何でvoid*なのか一瞬考えたことがあったので、明示するのは悪くないと思います。
> > 混ざってるならそれは見落としですね。
> 
>  個人的には,opaque ってなんじゃらと混乱しましたので,よくわからんポイ
> ンタだとわかる void * のほうが好きなのですが.hoge_opaque_t ってのは,よ
> く知られた表現なんですかね?
> 
>  この辺は,bikeshed になるでしょうか.どうしたもんですかね.

どう考えてもbikeshedだよなあ、と思いますが、敢えて参戦します。
まず、rb_opaque_tというのは何も「明示」してないので、void *と
比べてマシになっているとは思えません。
名前の付けられない何かであるということを明示したいのなら、
void *で十分と思います。

実際には、rb_opaque_tを返す関数を見る限りでは、これはコンパイ
ル結果であろうことは容易に推察できます。
また、rb_opaque_tを受け取る関数を見る限りでは、これはnodeなの
であろうということも推察できます。
というわけで、「コンパイル結果でありnodeである」ということを
示す名前をつけるのが妥当ではないでしょうか。
あんまりいい名前ではないですが、rb_compiled_node_tとか。


それでは。
-- 
U.Nakamura <usa@garbagecollect•jp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45750] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15  9:29       ` [ruby-dev:45749] " U.Nakamura
@ 2012-06-15 12:41         ` Yugui
  2012-06-15 21:57           ` [ruby-dev:45754] " Nobuyoshi Nakada
  2012-06-18  2:42           ` [ruby-dev:45756] " U.Nakamura
  0 siblings, 2 replies; 19+ messages in thread
From: Yugui @ 2012-06-15 12:41 UTC (permalink / raw
  To: ruby developers list

2012/6/15 U.Nakamura <usa@garbagecollect•jp>:
> こんにちは、なかむら(う)です。
>
> In message "[ruby-dev:45748] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult"
>    on Jun.15,2012 17:29:57, <ko1@atdot•net> wrote:
>> > 何でvoid*なのか一瞬考えたことがあったので、明示するのは悪くないと思います。
>> > 混ざってるならそれは見落としですね。
>>
>>  個人的には,opaque ってなんじゃらと混乱しましたので,よくわからんポイ
>> ンタだとわかる void * のほうが好きなのですが.hoge_opaque_t ってのは,よ
>> く知られた表現なんですかね?
>>
>>  この辺は,bikeshed になるでしょうか.どうしたもんですかね.
>
> どう考えてもbikeshedだよなあ、と思いますが、敢えて参戦します。
> まず、rb_opaque_tというのは何も「明示」してないので、void *と
> 比べてマシになっているとは思えません。
> 名前の付けられない何かであるということを明示したいのなら、
> void *で十分と思います。
>
> 実際には、rb_opaque_tを返す関数を見る限りでは、これはコンパイ
> ル結果であろうことは容易に推察できます。
> また、rb_opaque_tを受け取る関数を見る限りでは、これはnodeなの
> であろうということも推察できます。
> というわけで、「コンパイル結果でありnodeである」ということを
> 示す名前をつけるのが妥当ではないでしょうか。
> あんまりいい名前ではないですが、rb_compiled_node_tとか。

NODEじゃないんですよね実は。受け取る関数の名前は単なる1.8時代の名残であって現在はiseqです。
こんな風に、APIレベルでは中身について詮索すると幸せにならないのでopaque dataとしてあつかってほしい訳です。
void*でもruby_opaque_tでも変わらないよ、というのは一つの意見としてあり得ますが、今更nodeというのはないと思います。

>
>
> それでは。
> --
> U.Nakamura <usa@garbagecollect•jp>
>
>



-- 
Yuki Sonoda (Yugui)
yugui@yugui•jp
http://yugui.jp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45751] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15  8:29     ` [ruby-dev:45748] " SASADA Koichi
  2012-06-15  9:29       ` [ruby-dev:45749] " U.Nakamura
@ 2012-06-15 13:02       ` Yugui
  2012-06-18 19:39         ` [ruby-dev:45761] " SASADA Koichi
  1 sibling, 1 reply; 19+ messages in thread
From: Yugui @ 2012-06-15 13:02 UTC (permalink / raw
  To: ruby developers list

2012/6/15 SASADA Koichi <ko1@atdot•net>:
>  ささだです.
>
> (2012/06/15 16:30), Yugui wrote:
>>> ...
>>>> +/**
>>>> + * @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 * と混ざっているよう
>>> ですが.
>>
>> 何でvoid*なのか一瞬考えたことがあったので、明示するのは悪くないと思います。
>> 混ざってるならそれは見落としですね。
>
>  個人的には,opaque ってなんじゃらと混乱しましたので,よくわからんポイ
> ンタだとわかる void * のほうが好きなのですが.hoge_opaque_t ってのは,よ
> く知られた表現なんですかね?

opaque pointerってのはよくある表現ですよね。

>
>  この辺は,bikeshed になるでしょうか.どうしたもんですかね.
>
>
>>>  構成的には,
>>>
>>> - 必須な項目
>>> - 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 とかって,これは埋め込みのためなんだろうか.
>>
>> Matzのcopyrightを表示したいというニーズはどこかにあるんじゃないですかね。
>> 少なくともextのためのものではないので。
>>
>> extのためのものでないAPIを一まとめにしてみました。
>
>  了解です.
>
>
>> ですです。使う必要が無いなら隠しても良いですが、互換性への配慮は必要ですね。
>> とりあえずdeprecated attributeでも付けてみますか?
>
>  この辺は別件として整理するべきでしょうか.
>
>
>>>> +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 だけじゃ駄目なんでしたっけ.つまり,
>>> ファイル名,もしくは文字列渡して実行するインターフェースだけだと不十分?
>
>  この点についてはどうでしょうか.
>
>  IRCNet#ruby-ja で,
>
>> 16:55 yugui      > 同じ式を繰り返し評価したいニーズは埋め込みでは結構
> あるので
>
> ということで,使い回したい,ということかと思うのですが,
>
> (1) 使い回すならメソッドとして定義したほうがよさそう
> (2) コンパイルするコストは本当に問題か?
>
> というのが気になります.これが無くなると,iseq を見せなくてよさそうだか
> ら(opaque ってなんだろうと思わなくて済むので),評価までやっちゃったほ
> うがいいじゃないかな,と思っています.
>
>
>>>  ファイル名を渡すなら,ruby_options でファイル名渡せば main で実行され
>>> ますんで,文字列で実行する版だけがあればよい?
>>
>> オプション解析がまったく余分です。
>
>  余分であって,出来ないわけじゃないですよね.困る場合はあるでしょう
> か.1つ思いついたのは,ファイル名を正しくクオートした文字列として渡さな
> いといけないのが困るかな,という点でした.
>
>  現状,Ruby への起動インターフェースをまとめたもの,ということかと思っ
> ています.
>
>
>>>> +int ruby_exec_node(ruby_opaque_t n);
>>>> +int ruby_eval_main(ruby_opaque_t n, VALUE *result);
>>>
>>>  eval_main というのが適切か自信がありません.eval_in_main_context とか
>>> だと冗長でしょうか.
>>
>> それでもいいかもしれません。
>
>  あと,Kernel.eval というのは文字列をとるので,iseq を受け取るインター
> フェースは混乱しそうな気がします(なので,上で述べた文字列を受け取り評価
> までするほうがいいんじゃないかな,と思っています).

コンパイルコストが本当に必要になるケースがはっきりしてくるまでは、まずはそれで良いかもしれません。
じゃ、ruby_compile_main_from_string と ruby_eval_main は削除しましょう。

ここで案が2つあります。
1. toplevel_binding と rb_f_evalを公開する
2. さらに両者を合わせてruby_eval_in_main みたいなのを作る。

どっちが良いと思います?
ちなみに、いずれにしてもさらにファイル版は必要だと思います。というのはマジックコメントとか読んで
適切なエンコーディングを付けたりってのは結構面倒なので。
で、そのエンコーディングを付ける話を始めるとまたencdet話に跳んでしまうので、
* rb_eval_string_in_main
* rb_eval_file_in_main
を作るのが現実的かなと思ってます。

>
>
>>>> 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 が成功ってのは,ほかもありましたっけ.
>>
>> この辺の関数は全部exit(3)に渡す前提なので0が成功ですね。
>
>  了解です.
>
>  気になったのが,内部で使う分には「気を付けよう」で済むのが,外部へ出す
> となると,0失敗,1成功,のほうがわかりやすいかな,と思ったのでした.
>
>  返値を ruby_exit_code_t という型にすると,ちょっとわかりやすくなるかも
> しれませんね.
>
>
> --
> // SASADA Koichi at atdot dot net
>



-- 
Yuki Sonoda (Yugui)
yugui@yugui•jp
http://yugui.jp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45754] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15 12:41         ` [ruby-dev:45750] " Yugui
@ 2012-06-15 21:57           ` Nobuyoshi Nakada
  2012-06-18  8:14             ` [ruby-dev:45758] " KOSAKI Motohiro
  2012-06-18  2:42           ` [ruby-dev:45756] " U.Nakamura
  1 sibling, 1 reply; 19+ messages in thread
From: Nobuyoshi Nakada @ 2012-06-15 21:57 UTC (permalink / raw
  To: ruby developers list

なかだです。

At Fri, 15 Jun 2012 21:41:32 +0900,
Yugui wrote in [ruby-dev:45750]:
> NODEじゃないんですよね実は。受け取る関数の名前は単なる1.8時代の名残であって現在はiseqです。
> こんな風に、APIレベルでは中身について詮索すると幸せにならないのでopaque dataとしてあつかってほしい訳です。
> void*でもruby_opaque_tでも変わらないよ、というのは一つの意見としてあり得ますが、今更nodeというのはないと思います。

それならコンパイル結果であることを示す名前にすべきじゃないでしょ
うか。rb_opaque_tではopaqueなことはわかりますが、肝心の「何を
opaqueにしたのか」が不明です。重要なのは、opaqueであることではな
くてコンパイル結果であることのはずです。
もし他にもAPIレベルでは中身を見せたくないデータが必要になった場
合、やはりrb_opaque_tを流用するのでしょうか。

-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45755] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15  7:30   ` [ruby-dev:45747] " Yugui
  2012-06-15  8:29     ` [ruby-dev:45748] " SASADA Koichi
@ 2012-06-15 22:01     ` Nobuyoshi Nakada
  2012-06-18 19:49     ` [ruby-dev:45762] " SASADA Koichi
  2 siblings, 0 replies; 19+ messages in thread
From: Nobuyoshi Nakada @ 2012-06-15 22:01 UTC (permalink / raw
  To: ruby developers list

なかだです。

At Fri, 15 Jun 2012 16:30:28 +0900,
Yugui wrote in [ruby-dev:45747]:
> >> +/* Initializes the Ruby VM and builtin libraries.
> >> + * @retval 0 if succeeded.
> >> + * @retval non-zero an error occured.
> >> + */
> >> +int
> >> +ruby_setup(void)
> >>  {
> >
> >  0 が成功ってのは,ほかもありましたっけ.
> 
> この辺の関数は全部exit(3)に渡す前提なので0が成功ですね。

なら0を返すのは誤りです。EXIT_SUCCESSを返してください。

-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45756] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15 12:41         ` [ruby-dev:45750] " Yugui
  2012-06-15 21:57           ` [ruby-dev:45754] " Nobuyoshi Nakada
@ 2012-06-18  2:42           ` U.Nakamura
  2012-06-18  3:48             ` [ruby-dev:45757] " NARUSE, Yui
  1 sibling, 1 reply; 19+ messages in thread
From: U.Nakamura @ 2012-06-18  2:42 UTC (permalink / raw
  To: ruby developers list

こんにちは、なかむら(う)です。

In message "[ruby-dev:45750] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult"
    on Jun.15,2012 21:41:32, <yugui@yugui•jp> wrote:
> NODEじゃないんですよね実は。受け取る関数の名前は単なる1.8時代の名残であって現在はiseqです。

なのでNODEと書かずにnodeと書いてるわけですが、関数の名前が間
違ってるのであれば本当はそれも正すべきですよね。
この名前は今回のタイミングで変えられないんでしたっけ?

# と、無駄に話が広がるから手を出しにくい。


> こんな風に、APIレベルでは中身について詮索すると幸せにならないのでopaque dataとしてあつかってほしい訳です。
> void*でもruby_opaque_tでも変わらないよ、というのは一つの意見としてあり得ますが、今更nodeというのはないと思います。

opaqueがなんでいけないのかはなかださんが述べてるので略。


それでは。
-- 
U.Nakamura <usa@garbagecollect•jp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45757] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-18  2:42           ` [ruby-dev:45756] " U.Nakamura
@ 2012-06-18  3:48             ` NARUSE, Yui
  0 siblings, 0 replies; 19+ messages in thread
From: NARUSE, Yui @ 2012-06-18  3:48 UTC (permalink / raw
  To: ruby developers list

2012年6月18日 11:42 U.Nakamura <usa@garbagecollect•jp>:
> こんにちは、なかむら(う)です。
>
> In message "[ruby-dev:45750] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult"
>    on Jun.15,2012 21:41:32, <yugui@yugui•jp> wrote:
>> NODEじゃないんですよね実は。受け取る関数の名前は単なる1.8時代の名残であって現在はiseqです。
>
> なのでNODEと書かずにnodeと書いてるわけですが、関数の名前が間
> 違ってるのであれば本当はそれも正すべきですよね。
> この名前は今回のタイミングで変えられないんでしたっけ?

rb_str_new シリーズのように、あるべき名前を新設して、互換性確保のために
旧名は alias するという技がありますから、変えられない理由はないはずですね。

-- 
NARUSE, Yui  <naruse@airemix•jp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45758] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15 21:57           ` [ruby-dev:45754] " Nobuyoshi Nakada
@ 2012-06-18  8:14             ` KOSAKI Motohiro
  2012-06-18 14:19               ` [ruby-dev:45759] " Yugui
  0 siblings, 1 reply; 19+ messages in thread
From: KOSAKI Motohiro @ 2012-06-18  8:14 UTC (permalink / raw
  To: ruby developers list; +Cc: kosaki.motohiro

(6/15/12 5:57 PM), Nobuyoshi Nakada wrote:
> なかだです。
> 
> At Fri, 15 Jun 2012 21:41:32 +0900,
> Yugui wrote in [ruby-dev:45750]:
>> NODEじゃないんですよね実は。受け取る関数の名前は単なる1.8時代の名残であって現在はiseqです。
>> こんな風に、APIレベルでは中身について詮索すると幸せにならないのでopaque dataとしてあつかってほしい訳です。
>> void*でもruby_opaque_tでも変わらないよ、というのは一つの意見としてあり得ますが、今更nodeというのはないと思います。
> 
> それならコンパイル結果であることを示す名前にすべきじゃないでしょ
> うか。rb_opaque_tではopaqueなことはわかりますが、肝心の「何を
> opaqueにしたのか」が不明です。重要なのは、opaqueであることではな
> くてコンパイル結果であることのはずです。
> もし他にもAPIレベルでは中身を見せたくないデータが必要になった場
> 合、やはりrb_opaque_tを流用するのでしょうか。

わたしも rb_opaque_t はちょっとないかなあと思います。普通汎用のopaque型ってのは
containerライブラリとか本当にcallerが何入れてくるか分からないときに使うテクニックなので、
nodeっぽいなにかな型をつくるなり、void*なんだけど変数名にて説明するのがいいと思います。

まあ、opaqueは枝葉の問題なのでさておくとして、なんで embedded feature が壊れるかと考えたん
ですが、ようするにテストが足りてない、gorubyではembedded featureが壊れたときにビルドが壊れる
ほどには本気embeddedではなかったということではないでしょうかね。なんか埋め込みサンプルを
もう1つぐらい treeに入れておくと幸せになれるように思うのですがどうでしょうか。

・・・などという事が、あーdiffにtestがないなあなどと思いながら眺めていて浮かんできましたです。はい
あと、サンプルが増えると perfコマンドにrubyスクリプトを解釈できるようにさせようという野望を持っている
僕がちょっとだけ幸せになれます(^_^)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45759] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-18  8:14             ` [ruby-dev:45758] " KOSAKI Motohiro
@ 2012-06-18 14:19               ` Yugui
  0 siblings, 0 replies; 19+ messages in thread
From: Yugui @ 2012-06-18 14:19 UTC (permalink / raw
  To: ruby developers list; +Cc: kosaki.motohiro

2012/6/18 KOSAKI Motohiro <kosaki.motohiro@gmail•com>:
> (6/15/12 5:57 PM), Nobuyoshi Nakada wrote:
>> なかだです。
>>
>> At Fri, 15 Jun 2012 21:41:32 +0900,
>> Yugui wrote in [ruby-dev:45750]:
>>> NODEじゃないんですよね実は。受け取る関数の名前は単なる1.8時代の名残であって現在はiseqです。
>>> こんな風に、APIレベルでは中身について詮索すると幸せにならないのでopaque dataとしてあつかってほしい訳です。
>>> void*でもruby_opaque_tでも変わらないよ、というのは一つの意見としてあり得ますが、今更nodeというのはないと思います。
>>
>> それならコンパイル結果であることを示す名前にすべきじゃないでしょ
>> うか。rb_opaque_tではopaqueなことはわかりますが、肝心の「何を
>> opaqueにしたのか」が不明です。重要なのは、opaqueであることではな
>> くてコンパイル結果であることのはずです。
>> もし他にもAPIレベルでは中身を見せたくないデータが必要になった場
>> 合、やはりrb_opaque_tを流用するのでしょうか。
>
> わたしも rb_opaque_t はちょっとないかなあと思います。普通汎用のopaque型ってのは
> containerライブラリとか本当にcallerが何入れてくるか分からないときに使うテクニックなので、
> nodeっぽいなにかな型をつくるなり、void*なんだけど変数名にて説明するのがいいと思います。

枝葉の問題はさしたるこだわりもないし、なんだかいただいた意見が尤もに思えて来たのでそうするとしてですね。

> まあ、opaqueは枝葉の問題なのでさておくとして、なんで embedded feature が壊れるかと考えたん
> ですが、ようするにテストが足りてない、gorubyではembedded featureが壊れたときにビルドが壊れる
> ほどには本気embeddedではなかったということではないでしょうかね。なんか埋め込みサンプルを
> もう1つぐらい treeに入れておくと幸せになれるように思うのですがどうでしょうか。

テストも足すとしてですね。

* TOPLEVEL binding取得関数 + binding下で評価する関数
* TOPLEVEL binding専用の評価関数

とどっちの案が良いものか何かご意見はありますか。
私としては一応後者の案でパッチを書き進めているところです。

>
> ・・・などという事が、あーdiffにtestがないなあなどと思いながら眺めていて浮かんできましたです。はい
> あと、サンプルが増えると perfコマンドにrubyスクリプトを解釈できるようにさせようという野望を持っている
> 僕がちょっとだけ幸せになれます(^_^)
>
>



-- 
Yuki Sonoda (Yugui)
yugui@yugui•jp
http://yugui.jp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45761] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15 13:02       ` [ruby-dev:45751] " Yugui
@ 2012-06-18 19:39         ` SASADA Koichi
  2012-06-18 20:56           ` [ruby-dev:45763] " SASADA Koichi
  2012-06-21  0:15           ` [ruby-dev:45786] " Yugui
  0 siblings, 2 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-18 19:39 UTC (permalink / raw
  To: ruby developers list

 ささだです.

(2012/06/15 22:02), Yugui wrote:
> コンパイルコストが本当に必要になるケースがはっきりしてくるまでは、まずはそれで良いかもしれません。
> じゃ、ruby_compile_main_from_string と ruby_eval_main は削除しましょう。
> 
> ここで案が2つあります。
> 1. toplevel_binding と rb_f_evalを公開する
> 2. さらに両者を合わせてruby_eval_in_main みたいなのを作る。
> 
> どっちが良いと思います?
> ちなみに、いずれにしてもさらにファイル版は必要だと思います。というのはマジックコメントとか読んで
> 適切なエンコーディングを付けたりってのは結構面倒なので。
> で、そのエンコーディングを付ける話を始めるとまたencdet話に跳んでしまうので、
> * rb_eval_string_in_main
> * rb_eval_file_in_main
> を作るのが現実的かなと思ってます。

 返事が遅くなってすみません.長いメールになりましたが,ちゃんと議論しよ
うとすると,こういうふうにまとめないといかんと思って,それで面倒がって遅
れておりました.すみません.

 中田さんに協力してもらって,現在,Ruby を組み込んだアプリから Ruby プ
ログラムを実行する方法をまとめました.下記に示すように意外とある,という
か,あまり一貫性がなく追加しているので,あまり良くないなぁと,思っている
というのがありまして,なので慎重になっている次第です.


 プログラムを組み込んだアプリから指定して実行する,という時,気にしない
といけない点がいくつかあるかと思います.次の 5 項目としてまとめました.

(a) プログラムの文字列はどうやって渡すか?
(b) トップレベルの self はどうなるか?
(c) 実行バインディングはどうなるか?
(d) __FILE__ はどうなるか?
(e) エンコーディングはどうなるか?
(f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)


(1) ruby_options() を利用(-r,-e,ファイル名を指定,標準入力から入力)

 ruby(1) と同じ利用感が得られます.

 -e は,エンコーディングは下記のようになるようです.

http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
> なお、標準入力から読み込んだスクリプトや、コマンドラインオプション -e
で与えたスクリプトの場合は、magic comment がなかった場合、ロケールが
script encoding として用いられます。このため、1 行スクリプトを書く場合に
までいちいち magic comment を書く必要はありません。

 プログラムの __FILE__ を好き勝手に指定する方法はありません(勝手に決ま
ります).-r,ファイル名指定では,それぞれ読み込んだファイルの名前,-e
では,"-e" になります.

まとめますと,

(a) プログラムの文字列はどうやって渡すか?

 -r:ファイル名でファイルを指定(ファイルの中身がプログラム)
 -e:実行する文字列を C 文字列で指定
 ファイル名:ファイル名でファイルを指定(ファイルの中身がプログラム)
 標準入力から:標準入力から読む

(b) トップレベルの self はどうなるか?

 main になる(ruby -e self で得られるオブジェクトを,ここでは main と呼
ぶことにします).

(c) 実行バインディングはどうなるか?

-r:新しいバインディングを作って実行します.
 例えば,ruby -rfoo -e 'p a' とあって,foo.rb に a=1 とあったとして
も,-r と -e は別々の環境を指しているので -e で a が見つからないというエ
ラーになります.

それ以外:

 TOPLEVEL_BINDING になります.

 例えば,ruby -e 'a=1' -e 'p a' とすると,プログラムが 2 回実行されます
が,同じバインディングを共有しているため,問題無く2回目の実行で 1 が出力
されます.

(d) __FILE__ はどうなるか?

 下記に固定されます.

 -r:指定されたファイル名
 -e:"-e"
 ファイル名:ファイル名
 標準入力から:"-"

(e) エンコーディングはどうなるか?

 マジックコメントを見て判断.ただし,下記の例外があり.

http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
> なお、標準入力から読み込んだスクリプトや、コマンドラインオプション -e
で与えたスクリプトの場合は、magic comment がなかった場合、ロケールが
script encoding として用いられます。このため、1 行スクリプトを書く場合に
までいちいち magic comment を書く必要はありません。

(f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)

 構文エラー,実行時エラー,ともにエラーが起きたらバックトレースを標準エ
ラー出力に表示して終了します.


(2) VALUE rb_eval_string(const char *str)
    VALUE rb_eval_string_protect(const char *str, int *state)
    VALUE rb_eval_string_wrap(const char *str, int *state)

 eval という名前ですが,意に反して,実は Kernel.eval ではありません.判
りづらいですね.これがまさに,Ruby を組み込んだアプリから使うことを意識
して作ったインターフェースです.多分.

 str で指定された C 文字列を実行します.-e に似ています.ただし,実行コ
ンテキストは TOPLEVEL_BINDING ではありません.self は main  です.これ
は,require された時のコンテキストと同じです.

 __FILE__ は "(eval)" 固定です.

 protect は,例外が起きたとき,外に例外が伝搬しません.state にどういう
実行状態で止まったか,ということが入ります.

 wrap は,protect の機能に加えて,load で第2引数を true にしたときに
toplevel に匿名 module が指定されますが,それと同じ挙動を行います.

 実は,yugui さんが欲しいのは,__FILE__ が指定出来ない,という点以外は
これなんじゃないかと思うのですが,どうでしょうか.TOPLEVEL_BINDING で実
行したい,というのは,本当に必要な要件なんでしょうか.


 まとめます.

(a) プログラムの文字列はどうやって渡すか?

 C 文字列で渡します.

(b) トップレベルの self はどうなるか?

 main になります.

(c) 実行バインディングはどうなるか?

 新しい binding を作って実行します.require で新しく作られるバインディ
ングと同じです.

 rb_eval_string_wrap() の場合,定数のトップレベルが匿名モジュールになり
ます.

(d) __FILE__ はどうなるか?

 "(eval)" になります.

(e) エンコーディングはどうなるか?

 マジックコメントを見ます.
(無いとどうなんだろう...)

(f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)

VALUE rb_eval_string(const char *str)
外側に伝搬します.アプリ側でトラップ出来るようにしておかないと死にます.

VALUE rb_eval_string_protect(const char *str, int *state)
VALUE rb_eval_string_wrap(const char *str, int *state)
エラーが起きたら state に 0 以外の値が入っています.


(3) void rb_load(VALUE fname, int wrap)
    void rb_load_protect(VALUE fname, int wrap, int *state)

 ファイル名を String で渡す,ということ以外は (2) と変わりません.

(a) プログラムの文字列はどうやって渡すか?

 ファイル名でファイルを指定(ファイルの中身がプログラム).

(b) トップレベルの self はどうなるか?

 main になります.wrap が !0 の場合,定数のトップレベルが匿名モジュール
になります.

(c) 実行バインディングはどうなるか?

 新しい binding を作って実行します.require で新しく作られるバインディ
ングと同じです.
 
(d) __FILE__ はどうなるか?

 渡されたファイル名と同じになります(多分).

(e) エンコーディングはどうなるか?

 マジックコメントを見ます.

(f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)

void rb_load(VALUE fname, int wrap)
  外側に伝搬します.設定していないと死にます(多分).

void rb_load_protect(VALUE fname, int wrap, int *state)
 ここで食い止めます.state を見るとエラーの有無をチェック出来ます.


(4) その他

 その他,Kernel.eval,Kernel.instance_eval,Kernel.class_eval などを用
いる,という手段もありますが,どちらかというと拡張ライブラリから呼び出す
ような手段であり,設定も面倒なので省略します.いや,それらで済むのなら,
それでいいのですが.

 ruby.h などで非公開の関数ですが rb_iseq_compile() + rb_iseq_eval() と
いうのもあるかと思ったんですが,よくよく調べてみると,これらをきちんと使
うのは準備が大変だということがわかりました.

 なお,上記で「準備しないと死ぬ」とあるのは,例外の伝搬先が設定されてい
ないと死ぬ,という感じです.普通に組込み用途でカジュアルに使わない方がい
いですね.


 とりあえず,現状認識はこの通りです.


 では,yugui さんご提案のインターフェースを見てます.

> * rb_eval_string_in_main
> * rb_eval_file_in_main

(a) プログラムの文字列はどうやって渡すか?

 不明.C 文字列だろうか.

(b) トップレベルの self はどうなるか?

 main です.

(c) 実行バインディングはどうなるか?

 TOPLEVEL_BINDING です.

(d) __FILE__ はどうなるか?

 不明.引数で渡すんだろうか.

(e) エンコーディングはどうなるか?

 多分,プログラム文字列に書いてあるのを読むんじゃないかと思う.

(f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)

 不明.



 ちなみに,組込みで有名な mruby さんのインターフェースを調べてみます.

int mrb_compile_file(mrb_state*,FILE*);
int mrb_compile_string(mrb_state*,char*);
int mrb_compile_nstring(mrb_state*,char*,size_t);

 ぱっと見た感じ,ファイルや C 文字列を渡すと,これらの関数は返値 n を返
し,コンパイル結果が mrb_state->ipre[n] に格納されます.

mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value);

 そして,mrb_run で,格納されたコンパイル結果を実行しています(多分).
第二引数に,コンパイル結果 mrb_state->irep[n] を mrb_proc_new() に渡して
Proc オブジェクトを作って(多分),第三引数にその Proc の初期値を渡して
実行,という感じでしょうか.多分.違ってたらすみません.

 まとめます.

(a) プログラムの文字列はどうやって渡すか?

 C 文字列や FILE*.

(b) トップレベルの self はどうなるか?

 どうなんだろう,これ.サンプル見ても判らなかったんだけど,main が勝手
に入るのかなぁ.

(c) 実行バインディングはどうなるか?

 そもそも binding が存在しません.

(d) __FILE__ はどうなるか?

 どうなるんでしょうか? そもそもあるの?

$ bin/mruby -e 'p __FILE__'
"(null)"
$ bin/mruby t.rb # t.rb には p __FILE__ と書いてある
"t.rb"

あるようでした.いつの間に設定されてたんだろう.mrb_compile_* だと,何が
入るんだろう.

(e) エンコーディングはどうなるか?

 エンコーディングが存在しません(多分.あったらすみません)

(f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)

 どうなるんでしょう? mrb_run() の外まで伝搬するのかなぁ.

 これでサーベイを終わります.JRuby とかも調べ出すといいんでしょうが,
ちょっとしんどくなってきました.



 こう見ると,VALUE rb_eval_string_protect(const char *str, int *state)
が,__FILE__ を指定出来ない(そして名前が Kernel.eval を想起させる悪い名
前である),という点以外はいけてるんじゃないかと思うのですが,どうでしょ
うか.

 アプリケーション組込みアプリが,TOPLEVEL_BINDING 上で動作する,という
のは,実は想定していませんでした(なので無かった).require 相当が動けば
いいと思っていました.

 やりたいときは,

    $exec_string にプログラムをセットしてから,
    rb_eval_string_protected("eval($exec_string, TOPLEVEL_BINDING)"...);

なんて手もあるかもしれません,がそれはあんまりかな.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45762] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-15  7:30   ` [ruby-dev:45747] " Yugui
  2012-06-15  8:29     ` [ruby-dev:45748] " SASADA Koichi
  2012-06-15 22:01     ` [ruby-dev:45755] " Nobuyoshi Nakada
@ 2012-06-18 19:49     ` SASADA Koichi
  2 siblings, 0 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-18 19:49 UTC (permalink / raw
  To: ruby developers list

 ささだです.

(2012/06/15 16:30), Yugui wrote:
>> >> +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 だけじゃ駄目なんでしたっけ.つまり,
>> ファイル名,もしくは文字列渡して実行するインターフェースだけだと不十分?

 余談ですが,このアプローチは根本的に不味いと言うことに気づきました.

 Kernel.eval(src, TOPLEVEL_BINDING) 相当を目指していると思うのですが,
このために src から作る iseq は,実は渡した TOPLEVEL_BINDING の状態に応
じて異なります.


 例で示します.

    src = "a = 1"

という場合,a というローカル変数へ代入というとても簡単なコードなんですが,

  b = binding
  eval(src, b)     # この時は,自分の環境に a を作るので,
                   # setdynamic(i_idx, 0) という命令になる
  eval("x = 1", b) # 新しい変数 x が加わるので,b の環境が増える
  eval(src, b)     # 2 つ上の環境の a へ値をセットするので
                   # setdynamic(i_idx, 2) という命令になる

 同じスクリプトをコンパイルしていますが,b の状態に応じてコンパイル結果
が異なっています.

※マルチスレッドとか考えたくないですね....


 というわけで,コンパイル結果を保存して再利用,というのは原理的に無理で
した.

 [ruby-dev:45761] で述べた rb_eval_string() だと,環境は毎回新しいもの
になるので,コンパイル結果を使い回しすることが出来ます(細かいことを言う
と,グローバルに決まるコンパイルオプションを変えたときどうなるか,は違う
のですが).

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45763] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-18 19:39         ` [ruby-dev:45761] " SASADA Koichi
@ 2012-06-18 20:56           ` SASADA Koichi
  2012-06-21  0:15           ` [ruby-dev:45786] " Yugui
  1 sibling, 0 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-18 20:56 UTC (permalink / raw
  To: ruby developers list

訂正です.

(2012/06/19 4:39), SASADA Koichi wrote:
> (1) ruby_options() を利用(-r,-e,ファイル名を指定,標準入力から入力)
 + ruby_run_node() でした.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45786] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-18 19:39         ` [ruby-dev:45761] " SASADA Koichi
  2012-06-18 20:56           ` [ruby-dev:45763] " SASADA Koichi
@ 2012-06-21  0:15           ` Yugui
  2012-06-21  6:20             ` [ruby-dev:45787] " SASADA Koichi
  1 sibling, 1 reply; 19+ messages in thread
From: Yugui @ 2012-06-21  0:15 UTC (permalink / raw
  To: ruby developers list

2012/6/19 SASADA Koichi <ko1@atdot•net>:
>  ささだです.
>
> (2012/06/15 22:02), Yugui wrote:
>> コンパイルコストが本当に必要になるケースがはっきりしてくるまでは、まずはそれで良いかもしれません。
>> じゃ、ruby_compile_main_from_string と ruby_eval_main は削除しましょう。
>>
>> ここで案が2つあります。
>> 1. toplevel_binding と rb_f_evalを公開する
>> 2. さらに両者を合わせてruby_eval_in_main みたいなのを作る。
>>
>> どっちが良いと思います?
>> ちなみに、いずれにしてもさらにファイル版は必要だと思います。というのはマジックコメントとか読んで
>> 適切なエンコーディングを付けたりってのは結構面倒なので。
>> で、そのエンコーディングを付ける話を始めるとまたencdet話に跳んでしまうので、
>> * rb_eval_string_in_main
>> * rb_eval_file_in_main
>> を作るのが現実的かなと思ってます。
>
>  返事が遅くなってすみません.長いメールになりましたが,ちゃんと議論しよ
> うとすると,こういうふうにまとめないといかんと思って,それで面倒がって遅
> れておりました.すみません.
>
>  中田さんに協力してもらって,現在,Ruby を組み込んだアプリから Ruby プ
> ログラムを実行する方法をまとめました.下記に示すように意外とある,という
> か,あまり一貫性がなく追加しているので,あまり良くないなぁと,思っている
> というのがありまして,なので慎重になっている次第です.
>
>
>  プログラムを組み込んだアプリから指定して実行する,という時,気にしない
> といけない点がいくつかあるかと思います.次の 5 項目としてまとめました.
>
> (a) プログラムの文字列はどうやって渡すか?
> (b) トップレベルの self はどうなるか?
> (c) 実行バインディングはどうなるか?
> (d) __FILE__ はどうなるか?
> (e) エンコーディングはどうなるか?
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
>
> (1) ruby_options() を利用(-r,-e,ファイル名を指定,標準入力から入力)
>
>  ruby(1) と同じ利用感が得られます.
>
>  -e は,エンコーディングは下記のようになるようです.
>
> http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
>> なお、標準入力から読み込んだスクリプトや、コマンドラインオプション -e
> で与えたスクリプトの場合は、magic comment がなかった場合、ロケールが
> script encoding として用いられます。このため、1 行スクリプトを書く場合に
> までいちいち magic comment を書く必要はありません。
>
>  プログラムの __FILE__ を好き勝手に指定する方法はありません(勝手に決ま
> ります).-r,ファイル名指定では,それぞれ読み込んだファイルの名前,-e
> では,"-e" になります.
>
> まとめますと,
>
> (a) プログラムの文字列はどうやって渡すか?
>
>  -r:ファイル名でファイルを指定(ファイルの中身がプログラム)
>  -e:実行する文字列を C 文字列で指定
>  ファイル名:ファイル名でファイルを指定(ファイルの中身がプログラム)
>  標準入力から:標準入力から読む
>
> (b) トップレベルの self はどうなるか?
>
>  main になる(ruby -e self で得られるオブジェクトを,ここでは main と呼
> ぶことにします).
>
> (c) 実行バインディングはどうなるか?
>
> -r:新しいバインディングを作って実行します.
>  例えば,ruby -rfoo -e 'p a' とあって,foo.rb に a=1 とあったとして
> も,-r と -e は別々の環境を指しているので -e で a が見つからないというエ
> ラーになります.
>
> それ以外:
>
>  TOPLEVEL_BINDING になります.
>
>  例えば,ruby -e 'a=1' -e 'p a' とすると,プログラムが 2 回実行されます
> が,同じバインディングを共有しているため,問題無く2回目の実行で 1 が出力
> されます.
>
> (d) __FILE__ はどうなるか?
>
>  下記に固定されます.
>
>  -r:指定されたファイル名
>  -e:"-e"
>  ファイル名:ファイル名
>  標準入力から:"-"
>
> (e) エンコーディングはどうなるか?
>
>  マジックコメントを見て判断.ただし,下記の例外があり.
>
> http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
>> なお、標準入力から読み込んだスクリプトや、コマンドラインオプション -e
> で与えたスクリプトの場合は、magic comment がなかった場合、ロケールが
> script encoding として用いられます。このため、1 行スクリプトを書く場合に
> までいちいち magic comment を書く必要はありません。
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
>  構文エラー,実行時エラー,ともにエラーが起きたらバックトレースを標準エ
> ラー出力に表示して終了します.
>
>
> (2) VALUE rb_eval_string(const char *str)
>    VALUE rb_eval_string_protect(const char *str, int *state)
>    VALUE rb_eval_string_wrap(const char *str, int *state)
>
>  eval という名前ですが,意に反して,実は Kernel.eval ではありません.判
> りづらいですね.これがまさに,Ruby を組み込んだアプリから使うことを意識
> して作ったインターフェースです.多分.
>
>  str で指定された C 文字列を実行します.-e に似ています.ただし,実行コ
> ンテキストは TOPLEVEL_BINDING ではありません.self は main  です.これ
> は,require された時のコンテキストと同じです.
>
>  __FILE__ は "(eval)" 固定です.
>
>  protect は,例外が起きたとき,外に例外が伝搬しません.state にどういう
> 実行状態で止まったか,ということが入ります.
>
>  wrap は,protect の機能に加えて,load で第2引数を true にしたときに
> toplevel に匿名 module が指定されますが,それと同じ挙動を行います.
>
>  実は,yugui さんが欲しいのは,__FILE__ が指定出来ない,という点以外は
> これなんじゃないかと思うのですが,どうでしょうか.TOPLEVEL_BINDING で実
> 行したい,というのは,本当に必要な要件なんでしょうか.

なるほど。当面__FILE__の問題だけなんとかなれば要件としては十分そうです。

IRCでも話したように、これまでの議論と笹田さんの案から、
* ruby_opaque_t を void*に戻す

* ruby_compile_main_from_file
* ruby_compile_main_from_string
* ruby_eval_main
を削除

* rb_eval_string_with_filename(VALUE string, VALUE fname);
* rb_eval_string_with_filename_protect(VALUE string, VALUE fname, int* state);
を追加、

という提案をします。異論が無ければあとでコミットしますが、特に追加する関数の名前について何かご意見(もっと良い名前)は無いでしょうか。

>
>
>  まとめます.
>
> (a) プログラムの文字列はどうやって渡すか?
>
>  C 文字列で渡します.
>
> (b) トップレベルの self はどうなるか?
>
>  main になります.
>
> (c) 実行バインディングはどうなるか?
>
>  新しい binding を作って実行します.require で新しく作られるバインディ
> ングと同じです.
>
>  rb_eval_string_wrap() の場合,定数のトップレベルが匿名モジュールになり
> ます.
>
> (d) __FILE__ はどうなるか?
>
>  "(eval)" になります.
>
> (e) エンコーディングはどうなるか?
>
>  マジックコメントを見ます.
> (無いとどうなんだろう...)
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> VALUE rb_eval_string(const char *str)
> 外側に伝搬します.アプリ側でトラップ出来るようにしておかないと死にます.
>
> VALUE rb_eval_string_protect(const char *str, int *state)
> VALUE rb_eval_string_wrap(const char *str, int *state)
> エラーが起きたら state に 0 以外の値が入っています.
>
>
> (3) void rb_load(VALUE fname, int wrap)
>    void rb_load_protect(VALUE fname, int wrap, int *state)
>
>  ファイル名を String で渡す,ということ以外は (2) と変わりません.
>
> (a) プログラムの文字列はどうやって渡すか?
>
>  ファイル名でファイルを指定(ファイルの中身がプログラム).
>
> (b) トップレベルの self はどうなるか?
>
>  main になります.wrap が !0 の場合,定数のトップレベルが匿名モジュール
> になります.
>
> (c) 実行バインディングはどうなるか?
>
>  新しい binding を作って実行します.require で新しく作られるバインディ
> ングと同じです.
>
> (d) __FILE__ はどうなるか?
>
>  渡されたファイル名と同じになります(多分).
>
> (e) エンコーディングはどうなるか?
>
>  マジックコメントを見ます.
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
> void rb_load(VALUE fname, int wrap)
>  外側に伝搬します.設定していないと死にます(多分).
>
> void rb_load_protect(VALUE fname, int wrap, int *state)
>  ここで食い止めます.state を見るとエラーの有無をチェック出来ます.
>
>
> (4) その他
>
>  その他,Kernel.eval,Kernel.instance_eval,Kernel.class_eval などを用
> いる,という手段もありますが,どちらかというと拡張ライブラリから呼び出す
> ような手段であり,設定も面倒なので省略します.いや,それらで済むのなら,
> それでいいのですが.
>
>  ruby.h などで非公開の関数ですが rb_iseq_compile() + rb_iseq_eval() と
> いうのもあるかと思ったんですが,よくよく調べてみると,これらをきちんと使
> うのは準備が大変だということがわかりました.
>
>  なお,上記で「準備しないと死ぬ」とあるのは,例外の伝搬先が設定されてい
> ないと死ぬ,という感じです.普通に組込み用途でカジュアルに使わない方がい
> いですね.
>
>
>  とりあえず,現状認識はこの通りです.
>
>
>  では,yugui さんご提案のインターフェースを見てます.
>
>> * rb_eval_string_in_main
>> * rb_eval_file_in_main
>
> (a) プログラムの文字列はどうやって渡すか?
>
>  不明.C 文字列だろうか.
>
> (b) トップレベルの self はどうなるか?
>
>  main です.
>
> (c) 実行バインディングはどうなるか?
>
>  TOPLEVEL_BINDING です.
>
> (d) __FILE__ はどうなるか?
>
>  不明.引数で渡すんだろうか.
>
> (e) エンコーディングはどうなるか?
>
>  多分,プログラム文字列に書いてあるのを読むんじゃないかと思う.
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
>  不明.
>
>
>
>  ちなみに,組込みで有名な mruby さんのインターフェースを調べてみます.
>
> int mrb_compile_file(mrb_state*,FILE*);
> int mrb_compile_string(mrb_state*,char*);
> int mrb_compile_nstring(mrb_state*,char*,size_t);
>
>  ぱっと見た感じ,ファイルや C 文字列を渡すと,これらの関数は返値 n を返
> し,コンパイル結果が mrb_state->ipre[n] に格納されます.
>
> mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value);
>
>  そして,mrb_run で,格納されたコンパイル結果を実行しています(多分).
> 第二引数に,コンパイル結果 mrb_state->irep[n] を mrb_proc_new() に渡して
> Proc オブジェクトを作って(多分),第三引数にその Proc の初期値を渡して
> 実行,という感じでしょうか.多分.違ってたらすみません.
>
>  まとめます.
>
> (a) プログラムの文字列はどうやって渡すか?
>
>  C 文字列や FILE*.
>
> (b) トップレベルの self はどうなるか?
>
>  どうなんだろう,これ.サンプル見ても判らなかったんだけど,main が勝手
> に入るのかなぁ.
>
> (c) 実行バインディングはどうなるか?
>
>  そもそも binding が存在しません.
>
> (d) __FILE__ はどうなるか?
>
>  どうなるんでしょうか? そもそもあるの?
>
> $ bin/mruby -e 'p __FILE__'
> "(null)"
> $ bin/mruby t.rb # t.rb には p __FILE__ と書いてある
> "t.rb"
>
> あるようでした.いつの間に設定されてたんだろう.mrb_compile_* だと,何が
> 入るんだろう.
>
> (e) エンコーディングはどうなるか?
>
>  エンコーディングが存在しません(多分.あったらすみません)
>
> (f) エラーが起きたらどうなるか?(構文エラー,実行時エラー)
>
>  どうなるんでしょう? mrb_run() の外まで伝搬するのかなぁ.
>
>  これでサーベイを終わります.JRuby とかも調べ出すといいんでしょうが,
> ちょっとしんどくなってきました.
>
>
>
>  こう見ると,VALUE rb_eval_string_protect(const char *str, int *state)
> が,__FILE__ を指定出来ない(そして名前が Kernel.eval を想起させる悪い名
> 前である),という点以外はいけてるんじゃないかと思うのですが,どうでしょ
> うか.
>
>  アプリケーション組込みアプリが,TOPLEVEL_BINDING 上で動作する,という
> のは,実は想定していませんでした(なので無かった).require 相当が動けば
> いいと思っていました.
>
>  やりたいときは,
>
>    $exec_string にプログラムをセットしてから,
>    rb_eval_string_protected("eval($exec_string, TOPLEVEL_BINDING)"...);
>
> なんて手もあるかもしれません,がそれはあんまりかな.
>
> --
> // SASADA Koichi at atdot dot net
>



-- 
Yuki Sonoda (Yugui)
yugui@yugui•jp
http://yugui.jp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45787] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-21  0:15           ` [ruby-dev:45786] " Yugui
@ 2012-06-21  6:20             ` SASADA Koichi
  2012-06-21  6:58               ` [ruby-dev:45788] " SASADA Koichi
  2012-06-22 10:23               ` [ruby-dev:45793] " SASADA Koichi
  0 siblings, 2 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-21  6:20 UTC (permalink / raw
  To: ruby developers list

(2012/06/21 9:15), Yugui wrote:
> 
> * rb_eval_string_with_filename(VALUE string, VALUE fname);
> * rb_eval_string_with_filename_protect(VALUE string, VALUE fname, int* state);
> を追加、
> 
> という提案をします。異論が無ければあとでコミットしますが、特に追加する関数の名前について何かご意見(もっと良い名前)は無いでしょうか。

 いろいろ考えてたんですが,

rb_eval_string(const char *str)
を
rb_eval_string(const char *str, ...)
にしちゃうのはやっぱやり過ぎですかねぇ.第二引数があれば filename と考え
る,みたいな.

もう少し考えさせて下さい.

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45788] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-21  6:20             ` [ruby-dev:45787] " SASADA Koichi
@ 2012-06-21  6:58               ` SASADA Koichi
  2012-06-22 10:23               ` [ruby-dev:45793] " SASADA Koichi
  1 sibling, 0 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-21  6:58 UTC (permalink / raw
  To: ruby developers list

(2012/06/21 15:20), SASADA Koichi wrote:
> にしちゃうのはやっぱやり過ぎですかねぇ.第二引数があれば filename と考え
> る,みたいな.

ああ,すみません,変なことを書いていました.やっぱなしで.

あとは,Windows みたいに構造体のポインタ渡しとか...(Windows の場合は対
応する引数たっぷりの関数がありますが).

-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [ruby-dev:45793] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult
  2012-06-21  6:20             ` [ruby-dev:45787] " SASADA Koichi
  2012-06-21  6:58               ` [ruby-dev:45788] " SASADA Koichi
@ 2012-06-22 10:23               ` SASADA Koichi
  1 sibling, 0 replies; 19+ messages in thread
From: SASADA Koichi @ 2012-06-22 10:23 UTC (permalink / raw
  To: ruby developers list

(2012/06/21 15:20), SASADA Koichi wrote:
>> > 
>> > * rb_eval_string_with_filename(VALUE string, VALUE fname);
>> > * rb_eval_string_with_filename_protect(VALUE string, VALUE fname, int* state);
>> > を追加、
>> > 
>> > という提案をします。異論が無ければあとでコミットしますが、特に追加する関数の名前について何かご意見(もっと良い名前)は無いでしょうか。
...
> もう少し考えさせて下さい.

 ええと,本当に欲しいのは rb_ なのか ruby_ なのか,ってところでまた迷っ
ています.迷いすぎ.

 下記,考えながら書いているので,もし間違いがあればご指摘下さい.


ruby_ と rb_ の原則の整理:
(1) ruby_ なのは組み込み用.組み込むアプリが直接呼ぶ API.
(2) rb_ なのは基本的に拡張ライブラリ用 API.下記の制限がある.
  (2-1) すでに VM が初期化済みでなければならない.
  (ruby_ な関数にも,そういうのあるなぁ)
  (2-2) GET_THREAD() で rb_thread_t で取れるスレッドの情報に登録された
        ネイティブスレッドと動かすネイティブスレッドが同じでないといけ
        ない.
  (2-3) SAVE_ROOT_JMPBUF() で囲まれた部分から呼ばれたものじゃないと
     まずい... かも.例外が発生したときに最終的にどうなるか決めている.
  (2-4) GVL を獲得していなければいけない.


 上記に書いていますが,(2-1) は ruby_ でも同じですね.(2-2) も,そうい
うところがある.(2-3),(2-4) が rb_eval_string() ではまりそうです.

 (2-3) については,rb_eval_string_protect() で問題無い気がする.(2-4)
は,スレッドを切り替えなければ自然とそうなると思われる.だから,とりあえ
ずいいのかな.


 こういう懸念がある,という上で,後で変えるかもしれないけど,そんときは
そんとき,ということで突っ込んで頂いてもいいような気がします.お願いでき
ますか? やって頂ける場合は,他の取り下げたコードの revert なども一緒に
やって頂ければ(私のほうで revert しようかと思ったら,何がどうだったかわ
からなくなって断念しました).



----

 アプリ組込みについて,面倒なことといえば,まだシグナルハンドラとかの話
がありますね.その辺も,もうちょっと柔軟に出来る様にしたいと思っています.


アプリ組込み方法(案)
(1) 初級 ruby_options() を使う(お勧め)

(2) 中級 rb_eval_string_protect() を使う

(3) 上級(なんか新しく作る,細かい API)

みたいな感じに,色々用途によって変更できるといいなぁ,と思っています.上
級は inits から自分で自由にやるようなのを想定.

 これについての TODO:

- 上級用の,初期化 API
- アプリ <-> Ruby の通信路(標準的な転送手段)
- 関係無いネイティブスレッド上で安全に Ruby を走らせる方法
- ドキュメント


-- 
// SASADA Koichi at atdot dot net

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2012-06-22 10:26 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20120614022221.A45366858E@sakura.atdot.net>
2012-06-14 23:26 ` [ruby-dev:45745] Re: [ruby-changes:24028] yugui:r36079 (trunk): Embedding CRuby interpreter without internal headers has been difficult SASADA Koichi
2012-06-15  7:30   ` [ruby-dev:45747] " Yugui
2012-06-15  8:29     ` [ruby-dev:45748] " SASADA Koichi
2012-06-15  9:29       ` [ruby-dev:45749] " U.Nakamura
2012-06-15 12:41         ` [ruby-dev:45750] " Yugui
2012-06-15 21:57           ` [ruby-dev:45754] " Nobuyoshi Nakada
2012-06-18  8:14             ` [ruby-dev:45758] " KOSAKI Motohiro
2012-06-18 14:19               ` [ruby-dev:45759] " Yugui
2012-06-18  2:42           ` [ruby-dev:45756] " U.Nakamura
2012-06-18  3:48             ` [ruby-dev:45757] " NARUSE, Yui
2012-06-15 13:02       ` [ruby-dev:45751] " Yugui
2012-06-18 19:39         ` [ruby-dev:45761] " SASADA Koichi
2012-06-18 20:56           ` [ruby-dev:45763] " SASADA Koichi
2012-06-21  0:15           ` [ruby-dev:45786] " Yugui
2012-06-21  6:20             ` [ruby-dev:45787] " SASADA Koichi
2012-06-21  6:58               ` [ruby-dev:45788] " SASADA Koichi
2012-06-22 10:23               ` [ruby-dev:45793] " SASADA Koichi
2012-06-15 22:01     ` [ruby-dev:45755] " Nobuyoshi Nakada
2012-06-18 19:49     ` [ruby-dev:45762] " SASADA Koichi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).