1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Cを使ってRubyのメソッドを書く(その1)

Last updated at Posted at 2020-09-07

###目次
Cを使ってRubyのメソッドを書く(その1) <- ここ
Cを使ってRubyのメソッドを書く(その2) Numo::NArray
###はじめに
C++でRubyの拡張ライブラリを書く方法は、「C++を使ってRubyのメソッドを書く(その1)」にありますので参考にしてください。C++さえ書ければほとんど苦労せずにライブラリが作成できますので、自分で一から書かれるのでしたらそちらをお勧めします。

ここでは、Cで書かれた関数を拡張ライブラリにする方法を紹介します。C++でもCと同様の書き方ができますので、すでにCで書かれたライブラリがある場合にも使うことができます。

    1. はdouble, float, intなどの単純な変数に受け渡し、3.で文字列に受け渡し、4.で既存のライブラリを拡張ライブラリにする方法を紹介します。
      配列を受け渡す方法は(その2)を参考にしてください。

###1. コンパイラが提供する関数を呼び出す
SWIGインターフェース定義ファイルを書きます。
上の%{..%}の中にはヘッダファイルを読み込むか、ヘッダファイルに相当することを書きます。

test.i
%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と記述することでそれぞれの機能を持たせられます。

extconf.rb
require 'mkmf'
create_makefile("test") # モジュール名と同じに

Makefikeを作成するためのRubyプログラムです。

以上のファイルを同じフォルダの中に入れ、次のコマンドを実行します。

swig -ruby test.i
ruby extconf.rb
make

以上で、test.bundle(拡張子はOSにより異なります)ができあがります。
テスト用プログラムです。

test1.rb
require "./test"
p Test.floor(2.3)
p Test. modf(2.3)

###2. 自作の関数を呼び出す

単純な変数を受け渡しする関数を書いてみました。ごく普通のCの関数です。2倍の値を返す関数です。ポインタは使っていません。

test2.c
double twicefold_d(double x){
  return(x*2.0);
}
test.i
%module test
%{
double twicefold_d(double x);
%}

double twicefold_d(double x);

ヘッダファイルは作っていませんので、%{..%}の中にヘッダファイルに相当すること書きます。
extconf.rbファイルとコマンドは上と同じものを使ってください。
フォルダの中に.cや.cppなどのプログラムファイルがありましたら、全部コンパイルてリンクしようとしますので、不必要なファイルは入れておかないようにしましょう。

テスト用プログラムです。

test2.rb
require "./test"
p Test.twicefold_d(3.4)

###3. 自作の関数を呼び出す 文字列を渡す
文字列も関数に簡単に渡すことができます。

test3.c
#include "test3.h"
int string_length(char* str){
  return(strlen(str));
}
test3.h
#include <string.h>
int string_length(char* str);

ここではヘッダファイルを作っています。そう手間はかかりませんので、ヘッダファイルを作っておいた方が何かと便利なように思います。

test.i
%module test
%{
#include "test3.h"
%}

%include test3.h

同じくextconf.rbファイルとコマンドは上と同じものを使ってください。

test1.rb
require "./test"
p Test.string_length("abcd")

###4. 既存ライブラリを利用できるようにする

GSLの関数gsl_hypotとgsl_hypot3を使えるようにします。GSLのヘッダファイルを読み込んで2つの関数のインターフェースを定義しています。2つの関数はヘッダファイルからそのままコピーしているだけで変更はしておりません。

test.i
%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);
extconf.rb
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つは片方ずつ指定できます。

test4.rb
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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?