Ruby/Cpp

http://shinh.skr.jp/koneta/rubycpp.tgz

ブリッジを書かずに Ruby から C++ を触る実験。やってることとしては、 .so を dlopen して dlinfo して内容を libbfd で読んで、 libiberty でデマングルして保持、んで Ruby から new とか method_missing が呼ばれると適当にコンストラクタだのメソッドだのを libffi で呼ぶ。

Ruby 側コード

#!/usr/bin/env ruby

require 'rubycpp'

BankAccount = Cplusplus::declare_class("bankaccount", "BankAccount", 4)
b = BankAccount.new(100)
b.deposit(300)
p b.dollars

C++ 側コード

#include <stdio.h>

#include "bankaccount.h"

BankAccount::BankAccount(int d) { dollars_ = d; }
int BankAccount::dollars() { return dollars_; }
void BankAccount::set_dollars(int d) { dollars_ = d; }
void BankAccount::deposit(int d) { dollars_ += d; }
void BankAccount::withdraw(int d) { dollars_ -= d; }

実行結果

400

とまあ動いてるんだけど、色々ダメすぎる。これ以上がんばってもどうしても解決できない問題としては、

  • g++ では返り値の情報がマングルされたシンボルに無い (しゃーないから現状 int 決め打ち)
  • 継承関係がチェックできない
  • インライン関数が当然呼べない
  • クラスのサイズがわからない (しゃーないから引数で渡している)

やっぱ時代は D なんじゃないか。上の二つは環境依存オッケなら最初の二つはできるんじゃないかと思うけど。あと以下はやる気失せたからやっていない問題。

  • オーバーロードを解決していない
  • 一つの .so から一つのクラスしか拾えない
  • C++ 的には基本型な std::string に手が出てない
  • たぶん Linux のみ
  • メモリ解放してないなど、全体的に適当

うんやっぱ Io から D 呼ぼう。 D でめんどうなのは GC の処理だけだと思う、たぶん。ついでに D でどんな場合でも大丈夫な .dll の作り方とか、考えてたことをやってみると良いと思った。

どうでもいいけど。メソッドを呼ぶ時は第一引数をオブジェクトにして残りを一個ずつずらす…とかは常識チックとして、コンストラクタは void (*) (void*, ...) 型の関数で new で確保したメモリを第一引数につっこむ。

    void* p = _Znwj(4);         // void* _Znwj(int size);  (要するに new)
    void (*ctor) (void*) = fp;  // fp はコンストラクタの関数ポインタとして
    ctor(p);

などと。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h