プログラミング言語SML#解説 3.7.1版
10 SML#の拡張機能:Cとの直接連携

10.4 動的リンクライブラリの使用

これまで説明したC関数宣言

val id = _import "symbol" : type

symbolの名前を持つC関数を静的にリンクする指示です. SML#は,この宣言を含むプログラムをオブジェクトファイルに コンパイルする時,C関数の名前をリンカによって解決すべき外部名として 書き出します. C関数はリンク時にSML#のオブジェクトファイルと共にリンクさ れます. 対話型モードも第14章で説明す る分割コンパイルのしくみを使って実装されているため,この宣言は対話型モー ドでも使用できます.

しかしながら,実行時にしか分からないライブラリの関数などを利用し たい場合などは,この静的なリンクは使用できません. SML#は,そのような場合も対応できる動的リンク機能を以下 のモジュールとして提供しています.

structure DynamicLink : sig
  type lib
  type codeptr
  datatype scope = LOCAL | GLOBAL
  datatype mode = LAZY | NOW
  val dlopen : string -> lib
  val dlopen’ : string * scope * mode -> lib
  val dlsym : lib * string -> codeptr
  val dlclose : lib -> unit
end

これら関数は,Unix系OSで提供されている同名のシステムサービスと同 等の機能をもっています.

  • dlopenは,共有ライブラリの名前を受け取り,共有ライブラリをオー プンします.

  • dlopen’は,より詳細なオープン機能を指定できます. scopemodeは,OSのシステムサービスdlopenに それぞれ RTLD_LOCALRTLD_GLOBALおよび RTLD_LAZY, RTLD_NOW を指定します. 詳しくは,OSのdlopen関数のマニュアルを参照ください.

  • dlsymは, dlopenでオープンされた共有ライブラリとライ ブラリ内の関数名を受け取り,その関数へのポインタを返します.

  • dlcloseは,共有ライブラリをクローズします.

dlsymで返される関数ポインタは,以下の構文によって SML#の関数に変換することができます.

exp : _import type

expは,codeptr型を持つSML#の式です. typeは,静的リンクを行う_import宣言で 記述する型と同一の構文によって記述されたCの型です. この式は,対応するSML#の型を持つ式となります.

動的リンクライブラリの利用手順は以下の通りです.

  1. 1.

    C言語などで動的リンクライブラリを作成します. 例えばLinuxでgccコンパイラを用いる場合, -sharedスイッチを指定すれば作成できます.

  2. 2.

    SML#で以下のコードを実行します.

    1. (a)

      dlopenでライブラリをオープンします.

    2. (b)

      dlsymで関数ポインタを取り出します.

    3. (c)

      型を指定し,C関数をSML#の変数に束縛します.

10.2に動的リンクの利用例を示します. 共有ライブラリの作成はSML#によるコードの実行前であればい つでもよいので,リンク時には存在しないC関数なども,利用することができま す.

samle.cファイル: int f(int s) {
  return(s * 2);
}
実行例: $ gcc -shared -o sample.so sample.c
$ smlsharp
SML# version 1.00 (2012-04-02 JST) for x86-linux
# val lib = DynamicLink.dlopen "sample.so";
val lib = _ : lib
# val fptr = DynamicLink.dlsym(lib, "f");
val fptr = ptr : unit ptr
# val f = fptr : _import int -> int;
val f = _ : int -> int
# f 3;
val it = 6 : int
Figure 10.2: C関数の動的リンク