RubyからC++のクラスを使用する

RubyからC++のクラスを呼び出す例をまとめる。環境は以下の通り。

ANTLR(2.7.7)で生成されたC++によるパーサプログラムを、Rubyから呼び出すために調べたものをまとめてみた。ANTLRも3.0からはRubyも対象言語に含まれているので、わざわざC++のクラスを呼び出すこともなくなるだろう。

クラス定義

まず、C++のクラス定義から。

クラスExmapleのヘッダファイルと定義ファイルを用意する。

Exaple.hpp

// Example.hpp
#ifndef __Example_hpp
#define __Example_hpp

class Example
{
public:
  Example(void);
  ~Example(void);

  char* toUpper(char* str);
  char* toLower(char* str);
  void print(char* str1, char* str2, int num=1);

};

#endif

Example.cpp

// Exmaple.cpp
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include "Example.hpp"

Example::Example(void)
{
}

Example::~Example(void)
{
}

char* Example::toUpper(char* str)
{
  char* p = str;
  while(*p) {
    *p = toupper(*p);
    p++;
  }
  return str;
}

char* Example::toLower(char* str)
{
  char* p = str;
  while(*p) {
    *p = tolower(*p);
    p++;
  }
  return str;
}

void Example::print(char* str1, char* str2, int num)
{
  int i;
  for(i=0; i<num; i++) {
    std::cout << str1 << " " << str2 << " " << std::endl;
  }
}

呼び出し側のRubyプログラム

次に、Exampleクラスを使用するRubyプログラムex.rbを示す。

#!/usr/bin/env ruby

$:.unshift File.join(File.dirname(__FILE__), ".")
require 'example'

e = Example::Example.new

str1 = "aaa bbb ccc"
p e.toUpper(str1)
p str1
               
p e.toLower(str1)
p str1

e.print("Hello, ", "World!")
e.print("Print", "Message", 3)

C++クラスのラッパーを作成する

SWIGでクラスExampleのラッパーを作成する。

インタフェースファイルの作成

Exampleクラスのラッパーを指定するため、インタフェースファイルexample.iを以下のように作成する。

%module example
%{
#include "Example.hpp"
%}
%include Example.hpp
SWIGの実行

SWIGの実行は以下の通り。ラッパーファイルが生成される。

$ swig -c++ -ruby example.i
$ ls *.cxx
example_wrap.cxx
$

Maikefileを自動生成させる

自分で作ってもいいが、面倒なのでRubyで作ってもらう。
Makefile生成用のRubyプログラムextconf.rbを以下に示す。

extconf.rb

require 'mkmf'
$libs += " -lstdc++ "
create_makefile("example")

実行する。

$ ruby extconf.rb
$

ビルド

makeを実行する。また、SELinuxが設定されている場合は、chconコマンドを実行する必要がある。

$ make
...
$ chcon -t texrel_shlib_t example.so
$

実行

以下に実行結果を示す。

$ ruby ex.ruby
"AAA BBB CCC"
"AAA BBB CCC"
"aaa bbb ccc"
"aaa bbb ccc"
Hello,  World! 
Print Message 
Print Message 
Print Message 
$

まとめ

一連の作業を以下のようにスクリプトにしておくと便利。

$ cat build.sh
/bin/rm -fr *.so *.o *.cxx
swig -c++ -ruby example.i
ruby extconf.rb
make
chcon -t texrel_shlib_t example.so
$