MATLABからCライブラリを呼び出してみる
前回は、MEX関数を使ってMATLABからCコードを呼び出してみました。
今回は、すこしだけ発展させて、MEX関数をライブラリ化してMATLABから呼び出してみたいと思います。
https://jp.mathworks.com/help/matlab/call-c-library-functions.html
MATLABが呼び出すCライブラリのサンプルは、MATLABをインストールしたときに一緒にインストールされています。
以下のコマンドを使うことでサンプルプログラムがインストールされているパスを調べることができます。
今回はこのサンプルプログラムを参考にしました。
>> fullfile(matlabroot,'extern','examples','shrlib')
簡単なライブラリを作ってみる
以下はライブラリの実装例です。
構造体TEST_DATAのポインタを引数にもらって、そのメンバ変数を加算するadd()と減算するsub()を持っています。
MEX関数を作ったときと同様にmex.hをincludeしてmexFunction()を定義していますが、mexFunction()ではなにも行いません。
#include <mex.h> #include "test.h" __declspec(dllexport) double add(TEST_DATA* data) { double ret = 0; ret = data->p1 + data->p2 + data->p3; return ret; } __declspec(dllexport) double sub(TEST_DATA* data) { double ret = 0; ret = data->p1 - data->p2 - data->p3; return ret; } /* MEX関数インタフェース */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[]) { /* なにも行わない */ }
こちらはライブラリのヘッダファイルです。
構造体とMATLABから実行したい関数のプロトタイプを定義しておきます。
#ifndef TEST_H #define TEST_H typedef struct { double p1; double p2; double p3; } TEST_DATA; __declspec(dllexport) double add(TEST_DATA* data); __declspec(dllexport) double sub(TEST_DATA* data); #endif
動かしてみる
実行はMATLABコマンドラインから以下のように実行します。
% Cライブラリをビルド >> mex test.c 'Microsoft Visual C++ 2019 (C)' でビルドしています。 MEX は正常に完了しました。 % Cライブラリをロード >> loadlibrary('test', 'test.h'); % 構造体作成 >> st.p1 = 1; >> st.p2 = 2; >> st.p3 = 3; % ポインター オブジェクトを作成 >> p = libpointer('TEST_DATA', st); % 加算関数実行 >> a = calllib('test', 'add', p); >> a a = 6 % 減算関数実行 >> a = calllib('test', 'sub', p); >> a a = -4 % ワークスペースの変数をクリア >> clear % Cライブラリをアンロード >> unloadlibrary('test');
前回と同様に、mexを使用してビルドします。
ライブラリ名は同様にファイル名となります。
ビルド後はloadlibraryでライブラリを読み込みます。
このときMATLABから見えるCのインタフェースとしてヘッダファイルを指定します。
Cで定義したライブラリ関数はTEST_DATA型のポインタを引数に持ちます。
したがってMATLABではポインター オブジェクトを作成してやる必要があります。
ポインター オブジェクトはlibpointerで作成することができます。
ライブラリ関数はcalllibで呼び出すことができます。
引数にはライブラリ名、ライブラリ関数、ライブラリ関数が使用する引数を指定します。
ライブラリを使い終えたらunloadlibraryで開放します。
このときポインター オブジェクトを作成してライブラリ関数に引数として渡している、またはライブラリ関数の返値がポインター オブジェクトだった場合、
ワークスペースをクリアしない状態でunloadlibraryを呼ぶと以下のようなエラーが出ます。
したがってclear <変数名>を実行しておきます。
エラー: unloadlibrary 未解決オブジェクトをもつライブラリを解放できません。
以上がざっくりした使い方になります。
もうすこし詳しい使い方を知りたい場合は、サンプルのソースコードと公式ドキュメントを見れば、大体わかると思います!