CプログラムからPerlインタプリタを呼ぶ方法


注意:
Windows開発者向けのドキュメントです。あと、これは私がすっごい悩んだ はらいせで書いているので「かなり間違っている」と思われます。
もともとただのメモ書きだったのを、他の人にもヒント位にはなるだろうから 公開するだけです。
しかし、自分がWindowsのドキュメントを書くとは思わなかっ たなぁ。。

本題に入りましょう。Perlをいじったことのある人で、Cを書いている人なら おそらく一度は「俺のCプログラムの中にPerlインタプリタが入れられたらな あ」と思ったことがあるはずだと仮に仮定します。ましてやWindowsのバイナリ 配布をやってるActive Wareが配ってる Perlの移植版は、perl.dllというものが入っているので、「これを使ったら一発だ!」と 思って使ってみたいと思うのが人情というものだと仮定します。

そこで当然すぐさまPerl4のらくだ本をひもとくと、「Cサブルーチン をPerlにリンクする」という項があるので「これだ!」と思ったら例も なんにも載ってないし「特製のインタプリタを作る」って書いてあるか ら違いそうなので、英文のPerl5のらくだ本を辞書片手にみると 「ドキュメントはいっぱいあるけどここには書けないからperlembedと いうとっても詳細なマニュアルを読んで」とだけ書かれているので 「これだ!」と思ってマニュアルを見ると「perlmain.cをみてね」と 1行だけ書かれているので「これだ!」と思ってソースを見ようと 思ったらなぜか入ってなくて、miniperlmainというのがあったので 「これだ!」とおもって見るとコメントもなんにもなくてがっかりして ニューズグループの過去ログをみると、 「RE: PerlをCから呼ぶ>>>それはねー」というのが大量にあるので 「これだ!」と思って見るとPerl5らくだ本のまんま写しを解説してる奴 ばっかりで「結局あんたら分かってねーんじゃん」と突っ込みを 軽く入れてAltavistaで検索をかけたらありましたよ、1件だけ。 perl100.dllを使ってPerlをCから制御する方法が。

それがこのWin32 perlembed... the real dealです。

書いてあるとおりにやったらうまく行ったので、そのままやり方を書いて おきます。僕が使ったのはPw32s315.zip + VisualC++Ver.5です。(だからドキュメントとソースの辻褄があっていなかったというのが種明しです)あと、本当に訳に立つperlembedのマニュアルへのリンクもそこから見つかったので書いておきます。

まず、Perllib.cppに、以下の行を追加する
int PERLLIBAPI PerlCallArgv(PerlHandle hPerl,char* subname, I32 flags, char** argv)
{
        int retval = 0;
        try
        {
                retval = ((CPerl*)hPerl)->perl_call_argv(subname, flags, argv);
        }
        catch (...)
        {
               ((CPerl*)hPerl)->fprintf(((CPerl*)hPerl)->GetpVtbl()->Stderr(), "%s\n", "Error: Runtime exception");
                retval = 0;
        }
        return retval;
}

NTpp.hについての記述があるが、135バージョンには見当たらなかった。

CPerlExeクラスの宣言の中に、以下のものを付け加える

inline int PerlCallArgv(char* subname, int flags, char** argv)
{
        return ::PerlCallArgv(hPerl, subname, flags, argv);
}

たとえば、sayhiというPerl関数だけ実行させたい時は、 perlexe.cppのmain()関数を次のように変える

void main(int argc, char **argv, char **env)
{
        int exitstatus = 1;
        CPerlExe exe;

        if(PerlGetVersion() << 107)
        {
                fprintf(stderr, "Perl.exe requires perl100.dll build 107 or later");
                exit(1);
                      exitstatus = exe.PerlCallArgv("sayhi",G_DISCARD | G_NOARGS, argv);
                }
                exe.PerlDestroy();
        }
        exit(exitstatus);
}

これでコンパイルして、

perl test.pl
のように起動すれば、test.plというファイルの[sayhi]関数だけがCから 実行される。

まあ結局は外からラッパーを掛けてるわけですな、多分。 あとは本家の文章をよんでください。