トップ «前の日記(2009-02-03) 最新 次の日記(2009-02-05)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2009-02-04

_ 組み込みRubyテンプレート

Ruby 1.9.1で組み込みRubyをプログラミングするには、1.8のときより必須事項が増えているので、それについて示してみます。ただしWin32用です。

以下が標準的なコード(C++用にしてみたり)となると思います。(20090206参照)


#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "ruby.h"
extern "C" {
#include "ruby/encoding.h"
}
static char* test_src[] = {
"begin\n",
"  require 'test/unit'\n",
"rescue => e\n",
"  puts \"#{e}\"\n",
"end\n",
"puts RUBY_VERSION\n",
"gets()\n",
"\n"};
 
int main(int argc, char* argv[])
{
#if defined(USE_ARGS)
    ruby_sysinit(argc, argv);
#else
    static int dummyargc(0);
    static char** vec;
    ruby_sysinit(&dummyargc, &vec);
#endif
    ruby_init();   // GC用にスタックポインタを設定、vmの起動
#if defined(USE_ARGS)
    ruby_options(argc, argv);
#else
    // ruby_options(process_options)の処理を肩代わり
    ruby_script("Embeded Ruby");    // BT採取で死ぬので必須
    VALUE enc = rb_enc_from_encoding(rb_locale_encoding());
    rb_enc_set_default_external(enc); // コメント欄参照。
    rb_enc_set_default_internal(enc); //
    ruby_init_loadpath();           // 常識的に必須(ruby/ver/arch,site_ruby,site_ruby/ver,site_ruby/ver/archなどが設定される)
#endif
    rb_require("win32ole");   // 拡張ライブラリのロード
    char szTemp[_MAX_PATH];
    GetTempPathA(_MAX_PATH, szTemp);
    char szTempFile[_MAX_PATH];
    GetTempFileNameA(szTemp, "rb1", 0, szTempFile);
    HANDLE h = CreateFile(szTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);
    for (int i = 0; i < sizeof(test_src)/sizeof(char*); i++) 
    {
        DWORD dw;
        WriteFile(h, test_src[i], strlen(test_src[i]), &dw, NULL);
    }
    CloseHandle(h);
    int state = 0;
    for (i = 0; szTempFile[i]; i++)
    {
        if (szTempFile[i] == '\\') szTempFile[i] = '/';
    }
    rb_load_protect(rb_str_new2(szTempFile), 0, &state);
    if (state)
    {
        printf("script error %d\n", state);
    }
    ruby_finalize();
    return 0;
}

問題点:win32では、fcloseがrb_w32_fcloseに置き換えられ、しかもそこでクラッシュする(fflushでINVALID FILE*になる)。……でも、win32/win32.cを読む限り、それはおかしいな。後で調べてみることにする。

本日のツッコミ(全15件) [ツッコミを入れる]
_ なるせ (2009-02-04 01:43)

default_external の設定が必要なのはわかりますが、rb_enc_set_default_internal(enc); はなくても動きませんか。<br>default_internal の機能が必要というのならわかりますが、まぁコメントには書いた方がいいでしょうね。

_ arton (2009-02-04 01:48)

どうもありがとうございます。<br>>rb_enc_set_default_internal(enc); はなくても動きませんか。<br>これは試してなかったので試してみます(良く分からないのでスキップした処理で関係しそうなやつを拾う、で動かしたからですね)。うまく動くようなら上のコメントアウトします。

_ arton (2009-02-04 01:52)

だめでした。ということは、Win32OLEの問題かな?<br>Win32OLEが、default_internalがnilの場合は、コードページをdefault_externalに設定しているからですね。というか、設定しない=nilで良いの?

_ なるせ (2009-02-04 10:15)

設定しない=nilですね。<br>nilを明示的にセットしないとダメなのかな、rb_enc_set_default_internal(Qnil);とか。<br>「ダメ」というのは先述のCP932とUS-ASCIIでなんとか?ってやつですかね。

_ arton (2009-02-04 12:44)

だめの意味はその通りです。あと、上ではnilと書いてしまいましたが、NULLですね。

_ なるせ (2009-02-04 14:46)

> Win32OLEが、default_internalがnilの場合は、コードページをdefault_externalに設定しているからですね<br>と、すると、Win32OLE 内の cp でなく、どこかで default_internal 設定の作用が働いてるのでしょう。<br><br>改めて確認しますが、CP932 と US-ASCII というメッセージは正確にはどんなメッセージでしたか。<br>少なくとも「CP932」は「Windows-31J」のはずです。<br><br>あと、rb_enc_check(fname, result);でエラーが発生しているとすると、<br>Windows-31J と US-ASCII だと compatible のはずです。<br>エラーが発生しているならば、fname も result も中に、<br>非 ASCII な文字列が紛れ込んでいると思われるんですが、<br>「'mini/test'の中でFile.expand_path __FILE__している箇所」だとすると、<br>イマイチここでそうなる理由がわかりません。

_ arton (2009-02-04 16:51)

1個思い出したことがあるので、夜になったら試すけど、エンコーディングが見つからない時の例外を避けるために(ruby_scriptに気付く前)空のCp932をencの下に置いて、そのままだったような気がする。それで、非互換なのかも。

_ arton (2009-02-04 22:12)

上の件は関係なかったようです(削除した)。エラーメッセージは、<br>incompatible character encodings: CP932 and US-ASCII<br>です。default_internalを設定すればエラーにならない(default_externalへの設定は影響しない)ことも同じでした。

_ arton (2009-02-05 00:06)

>少なくとも「CP932」は「Windows-31J」のはずです。 <br>Cp932というのは、win32ole.cのole_cp2encodingで作ったエンコーディングみたいですね。

_ arton (2009-02-05 00:09)

ソース読まずに考えると、default_internalにrb_enc_from_encoding(rb_locale_encoding())を設定することで、Cp932 エンコーディング(Windows31-Jのエイリアス?)が作成されて、Win32OLEがそれを利用できるようになるけれど、それをしないとCp932が存在しないので、Win32OLEがダミーのCp932を作り、それが利用され、しかもUS-ASCIIと非互換ということではないでしょうか?

_ なるせ (2009-02-05 05:24)

あー、直接的な原因はそれですね > Win32OLEがダミーのCp932を作り<br><br>ゆえに、今の謎は、<br>* なぜ CP932 で Windows-31J をとってこれないのか<br>* なぜ、rb_set_default_internal すると通るのか<br>ですか。<br><br><br>仮説としては、<br>まず、そもそも現在は組み込みエンコーディング (US-ASCII, ASCII-8BIT, UTF-8) しかとれておらず、Windows-31J は実はとれていない。<br>で、default_internal を設定すると通るのは、そもそも locale_encoding からして CP932 を取れていなくて ASCII-8BIT が入っている。defalt_internal にも locale_encoding = ASCII-8BIT が入り、Win32OLE は default_internal をコードページの代わりに使うのでダミーの CP932 を定義せず、動いているように見える。<br><br>検証するには、<br>* Encoding.list がどうなっているか見る→組み込みしかないのではないか<br>* Encoding.find("locale") がどうなっているかみる→ASCII-8BIT になっているのではないか<br>* 一見成功するとき rb_enc_check(fname, result);のfnameとresultがどうなっているか見る→ASCII-8BITとUS-ASCIIではないか<br><br>上のソースコードを見てもrb_enc_find_index("encdb");してるruby_optionsやprocess_optionsが通ってない可能性がありますし。

_ arton (2009-02-05 08:57)

むむ、rb_enc_find_index("encdb"); というのが必要なのか。というのはさておき、試してみます。

_ なかむら(う) (2009-02-05 10:07)

ruby_process_options()呼び出しは必須という形で設計されてるはずなので、無理に分解しないで素直に呼んだ方がいいと思います。

_ arton (2009-02-05 10:17)

1.9からは必須ということでもいいけど、ついでだから分解は、しときたいな。組み込んでいる側のコマンドラインをRubyに見せたくないって時に、安心感が得られるし。

_ arton (2009-02-06 02:02)

rb_enc_find_index('encdb')実行前は、US-ASCII,UTF-8だけで動いていて、default_external、default_internalのいずれの場合でもWin32OLEのダミーCP932が作られていました。<br>いずれの場合も$0はASCII-8BITになります。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|

ジェズイットを見習え