###目次
Cを使ってRubyのメソッドを書く(その1) <- ここ
Cを使ってRubyのメソッドを書く(その2) Numo::NArray
###はじめに
C++でRubyの拡張ライブラリを書く方法は、「C++を使ってRubyのメソッドを書く(その1)」にありますので参考にしてください。C++さえ書ければほとんど苦労せずにライブラリが作成できますので、自分で一から書かれるのでしたらそちらをお勧めします。
ここでは、Cで書かれた関数を拡張ライブラリにする方法を紹介します。C++でもCと同様の書き方ができますので、すでにCで書かれたライブラリがある場合にも使うことができます。
-
- はdouble, float, intなどの単純な変数に受け渡し、3.で文字列に受け渡し、4.で既存のライブラリを拡張ライブラリにする方法を紹介します。
配列を受け渡す方法は(その2)を参考にしてください。
- はdouble, float, intなどの単純な変数に受け渡し、3.で文字列に受け渡し、4.で既存のライブラリを拡張ライブラリにする方法を紹介します。
###1. コンパイラが提供する関数を呼び出す
SWIGインターフェース定義ファイルを書きます。
上の%{..%}の中にはヘッダファイルを読み込むか、ヘッダファイルに相当することを書きます。
%module test // モジュール名 最初の文字は大文字に変換される
%{
#include <math.h>
%}
%include "typemaps.i"
extern double floor(double x);
// double modf(double value, double *iptr); ポインタで値を受け取る時は*OUTPUTに変更
extern double modf(double value, double *OUTPUT);
下の方にはRubyから呼び出す関数を書いています。math.hには多くの関数のヘッダが書かれていますが、その中からfloorとmodfをRubyから利用できるようにします。
modfに2番目の引数はポインタになっておりdouble型の値を返します。ポインタでは入力、出力、入出力が可能で、*INPUT, *OUTPUT, *INOUTと記述することでそれぞれの機能を持たせられます。
require 'mkmf'
create_makefile("test") # モジュール名と同じに
Makefikeを作成するためのRubyプログラムです。
以上のファイルを同じフォルダの中に入れ、次のコマンドを実行します。
swig -ruby test.i
ruby extconf.rb
make
以上で、test.bundle(拡張子はOSにより異なります)ができあがります。
テスト用プログラムです。
require "./test"
p Test.floor(2.3)
p Test. modf(2.3)
###2. 自作の関数を呼び出す
単純な変数を受け渡しする関数を書いてみました。ごく普通のCの関数です。2倍の値を返す関数です。ポインタは使っていません。
double twicefold_d(double x){
return(x*2.0);
}
%module test
%{
double twicefold_d(double x);
%}
double twicefold_d(double x);
ヘッダファイルは作っていませんので、%{..%}の中にヘッダファイルに相当すること書きます。
extconf.rbファイルとコマンドは上と同じものを使ってください。
フォルダの中に.cや.cppなどのプログラムファイルがありましたら、全部コンパイルてリンクしようとしますので、不必要なファイルは入れておかないようにしましょう。
テスト用プログラムです。
require "./test"
p Test.twicefold_d(3.4)
###3. 自作の関数を呼び出す 文字列を渡す
文字列も関数に簡単に渡すことができます。
#include "test3.h"
int string_length(char* str){
return(strlen(str));
}
#include <string.h>
int string_length(char* str);
ここではヘッダファイルを作っています。そう手間はかかりませんので、ヘッダファイルを作っておいた方が何かと便利なように思います。
%module test
%{
#include "test3.h"
%}
%include test3.h
同じくextconf.rbファイルとコマンドは上と同じものを使ってください。
require "./test"
p Test.string_length("abcd")
###4. 既存ライブラリを利用できるようにする
GSLの関数gsl_hypotとgsl_hypot3を使えるようにします。GSLのヘッダファイルを読み込んで2つの関数のインターフェースを定義しています。2つの関数はヘッダファイルからそのままコピーしているだけで変更はしておりません。
%module test
%{
#include "gsl/gsl_math.h"
%}
extern double gsl_hypot(const double x, const double y);
extern double gsl_hypot3(const double x, const double y, const double z);
require 'mkmf'
dir_config("gsl")
have_header("gsl/gsl_math.h")
have_library("gsl") # libgsl.soをリンクする
create_makefile("test")
GSLのヘッダファイル読み込みとlibgsl.soをリンクする必要がありますので、そのための3行を追加しています。コマンドは上と同じで大丈夫なことが多いのですが、ヘッダファイルとlibgsl.soの場所がわからわからない時には次のようにruby extconf.rbに後にパスを書きます。
ruby extconf.rb -- --with-gsl-dir=/path
--with-gsl-include=/path/include
--with-gsl-lib=/path/lib
/path/include/gsl/gsl_math.hと/path/lib/libgsl.soのような場所にファイルがある時には
--with-gsl-dir=/pathで両方いっぺんに指定できます。下2つは片方ずつ指定できます。
require "./test"
p Test.gsl_hypot(3, 4)
p Test.gsl_hypot3(3, 4, 5)
CentOS 8.2 / Ruby 2.6.6 / Swig 3.0.12
macOS 10.13.6 / Ruby 2.7.1 / Swig 4.0.2