(13) [C&ML] C関数をMLから呼び出す

[ トップ | 目次 | 前ページ | 次ページ ]


演習1を実際にやってみると実感するであろうが,Cでは,関数を定義した後,その関数を呼び出すためにmain関数を書きその中に関数の呼び出しと結果をプリントするのコードを書き,関数の定義とともにファイルに格納し一緒にコンパイルして実行しなければならない.これに対してMLでは,定義した関数を対話型間環境から直接種々の値に対して呼び出してテストすることができる.これは,関数型言語の大きな利点の一つである.

Cの関数も,MLのように対話型環境から呼び出してテストできると便利である.SML#のCプログラムとの連携機能を使えば,簡単に実現することができる.この機能は,型とコンパイルに関する先端理論を駆使して実現された機能であるが,利用はいたって簡単である.今回は,SML#が提供するこの先端機能を学ぼう.

C関数を動的リンクライブラリとしてコンパイル

Cの関数をSML#の対話型環境から呼び出すには,呼び出したい関数をファイルに書き,それを動的リンクライブラリとしてコンパイルする.Cの関数定義で最初に定義したCのfactorial関数を例に説明する.

まず,factorial関数を含むファイルfact.cをいつもと通りCのソースを置くフォルダに作成する.

C:\SMLSharpAndC\c>type fact.c
type fact.c
int factorial (int x) {
  int s = 1;
  while (x > 0) {
    s = x * s;
    x = x - 1;
  }
  return (s);
}

C:\SMLSharpAndC\c>

次に,このファイルを動的リンクライブラリとしてコンパイルし結果をSML#が使用する動的リンクライブラリのためのフォルダに書き出す.以下のコマンドを実行するだけでよい.

C:\SMLSharpAndC\c>gcc -shared -o ../dllLib fact.c

ここで,gccコンパイラに新たに与えたスイッチの意味は以下の通りである.

  • -sharedは動的リンクライブラリとしてコンパイルする指示
  • -o ../dllLib/fact.dllは作成する動的リンクライブラリのパスの指定である.パスの中の..は一つ上のフォルダを指す.現在のフォルダがC:\SMLSharpAndC\cであるから,../dllLib/fact.dllはC:\SMLSharpAndC\dllLibを意味する.

動的リンクライブラリのためのフォルダは,作業用フォルダの作成と環境設定で作成し環境変数によってSML#コンパイラに通知済のはずである.

実際にライブラリが作られたかを確認してみよう.

C:\SMLSharpAndC\c>gcc -shared -o ../dllLib/fact.dll fact.c
gcc -shared -o ../dllLib/fact.dll fact.c

C:\SMLSharpAndC\c>cd ../dllLib
cd ../dllLib

C:\SMLSharpAndC\dllLib>dir
dir
 ドライブ C のボリューム ラベルは XXXX です
 ボリューム シリアル番号は YYYY です

 C:\SMLSharpAndC\dllLib のディレクトリ

2007/08/04  17:24    <DIR>          .
2007/08/04  17:24    <DIR>          ..
2007/08/04  17:24            12,978 fact.dll
               1 個のファイル              12,978 バイト
               2 個のディレクトリ  21,852,004,352 バイトの空き領域

C:\SMLSharpAndC\dllLib>

SML#から動的リンクライブラリの呼び出し

動的リンクライブラリの関数をSML#から利用するには,以下の2つを実行すればよい.

  1. DynamicLink.dlopen関数を用いて動的リンクライブラリのオープン.DynamicLink.dlopen関数の引数は動的リンクライブラリを表す文字列である.動的リンクライブラリを格納するフォルダがシステムのPATH変数として設定済であれば,ライブラリ名のみでよい.
  2. DynamicLink.dlsymと_import特殊構文を使って関数をインポート.DynamicLink.dlsymの引数は,DynamicLink.dlopenが返すライブラリハンドルと関数名の文字列である._import特殊構文は,DynamicLink.dlsymが取り出したCの関数ポインタをMLの関数に変換する処理を行う.この構文は以下のように指定する.
dlsym式 _import (引数1の型,...,引数Nの型) -> 結果の型

以下は,fact.dllのfactorial関数をインポートするコードである.

val libHandle = DynamicLink.dlopen "fact.dll";
val fact = DynamicLink.dlsym(libHandle, "factorial") : _import (int) -> int

smlのソースディレクトリに移動してこのコードを実行すると,以下のようにfactがSML#の関数として使用可能になる.

C:\SMLSharpAndC\dllLib>cd ../sml
cd ../sml

C:\SMLSharpAndC\sml>smlsharp
smlsharp
SML# 0.30 (2007-07-03 16:16:12 JST)
# val libHandle = DynamicLink.dlopen "fact.dll";
val libHandle = 0x10000000 : unit ptr
# val fact = DynamicLink.dlsym(libHandle, "factorial")
>             : _import (int) -> int;
val fact = fn : int  -> int
#

これ以降,factを通常のMLの関数と同様に使用することができる.

# fact 1;
val it = 1 : int
# fact 2;
val it = 2 : int
# fact 3;
val it = 6 : int
# fact 4;
val it = 24 : int
# fact 10 + 10;
val it = 3628810 : int
#

対話型環境からC関数をテストする.

以上の機能を使えば,Cの関数を対話型から簡単にテストすることができる.その標準の手順を作っておくと,CでもMLと同様の気軽さで種々の関数を定義し,システムを構築していくことができる.


[ トップ | 目次 | 前ページ | 次ページ ]