前回のエントリで、GCC-XML をビルドした。
今回は、それを利用して、CXXI に挑戦してみる。

CXXI とは

C++ と C# の相互運用するためのもの。
要するに、C# で C++ のクラスインスタンスを生成したり、
C++ クラス関数を呼び出したり、C++ クラスを派生したりできる(らしい)。
詳細は、以下のページ。

CXXI: Bridging the C++ and C# worlds. – Miguel de Icaza

同様の目的として使われるものは、

などがある。

Mono のインストール

公式ページから、最新のインストーラをダウンロードしてきて、C:\Mono にインストール。
MSYS の /etc/profile のラストに環境変数を書き加え、MSYS を再起動。

export C_INCLUDE_PATH=/usr/local/include
export CPLUS_INCLUDE_PATH=/usr/local/include
export LIBRARY_PATH=/usr/local/lib
export LD_LIBRARY_PATH=/usr/local/lib
export PKG_CONFIG_PATH=/usr/local/lib

# for Mono
export PATH=$PATH:/c/Mono/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/c/Mono/lib
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/c/Mono/lib/pkgconfig

Cxxi のインストール

Cxxi の github から、ソースコードをダウンロードしてくる。

$ wget https://github.com/mono/cxxi/tarball/master
$ tar fxz mono-cxxi-b079651.tar.gz
$ cd mono-cxxi-b079651
$ ./configure --enable-release --prefix=/c/Mono/
$ make
$ make install

(追記:2012/02/12) 順番が間違っていたので修正。

Cxxi のテスト

マネージコードから、ネイティブのクラスを使用してみる。
用いたコードは以下。

Native.hpp

namespace Sample
{
    class NativeClass
    {
    public:
        NativeClass();
        virtual ~NativeClass();
        int PrintNumber(int n);
    };
}

Native.cpp

#include <iostream>
#include "native.hpp"

Sample::NativeClass::NativeClass()
{
    std::cout << "ctor" << std::endl;
}

Sample::NativeClass::~NativeClass()
{
    std::cout << "dtor" << std::endl;
}

int Sample::NativeClass::PrintNumber(int n)
{
    std::cout << n << std::endl;
    return n;
}

Managed.cs

using System;
using Native.Sample;

namespace CxxiTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var native = new NativeClass())
            {
                native.PrintNumber(100);
            }
        }
    }
}

まずは、普通にネイティブな DLL を作成する。

$ g++ -shared -fPIC Native.cpp -o Native.dll

GCC-XML で C++ の ABI を解析し、XML に出力。

$ gccxml --gccxml-compiler "g++" --gccxml-cxxflags "-shared -fPIC" -fxml=Native.xml Native.hpp

XML を元に、C# コードを生成し、アセンブリを出力する。
`pkg-config –libs mono.cxxi` で Mono.Cxxi.dll のパスが引けるのだが、
MSYS 風のパス(/c/Mono/lib/mono-cxxi)では、gmcs が見つけることができない。
pkg-config の意味がなくなってしまうが、作業ディレクトリに Mono.Cxxi.dll をコピーする。

$ cp /c/Mono/lib/mono-cxxi/Mono.Cxxi.dll .
$ generator -o=generated --lib=Native Native.xml
$ gmcs -out:NativeWrapper.dll -target:library -unsafe -r:Mono.Cxxi.dll generated/*.cs

マネージコードから参照。

$ gmcs -out:Managed.exe -target:exe -r:Mono.Cxxi.dll,NativeWrapper.dll Managed.cs

動作させてみる。

$ ./Managed.exe
ctor
100
dtor

【参考】

たくまけい: MinGWでDLLを作ってみる (32bitと64bit)
CXXIがクロスプラットフォームでC++/C# interopを実現する(予定) – ものがたり