To Home
Created: Mon Jul 29 15:07:46 JST 2002
Last modified: Tue Dec 26 14:56:15 JST 2006

CamlIDL

概要

CamlからCのコードを呼ぶためのスタブコード生成器

使うために

入力ファイルの拡張子は .idl
Cのプロトタイプ宣言にちょっと(?)情報を付加したもの。
コメントは // , /* */ のようにC++スタイルである。

観察

quote(C,"[cのコード]") で Cのコード埋め込み
quote(call,"[cのコード]") で関数が呼び出された直後に埋め込むコードを指定できる。
  ↑ call/C のほかに....?
idlファイルから *_stubs.c を生成する。
[] 内に種々の制約情報をいれる。 in, out, サイズの情報など
いれられるものたち (Attributes)
ひきすうのみならず返り値にも指定する。(string, string*, null_terminated ...)

例と共に

tests/unix.idl
char** environment(void) で quote(call,"_res = environ;"); と変数束縛を行なうコードを埋め込んでいるが....。
なぞ _res って?
なぞ environ って?
解答 environ
  直前に長い quote(C,"...") がありこの中で environは宣言されている。
  extern char ** environ;
解答? _res
  対応するスタブコード value camlidl_unix_environment(value _unit) の中で宣言されている。 _res は返り値(Cの表現)を入れる局所変数のようだ。
  変数の命名規則?? (返り値のみでよいような気も??) 3.9 Functions で _res について述べられている。
callは、関数呼出部分を自分で書くためのもの。 スタブコードは以下の手順を踏む
  1. 前処理: 引数をMLの表現からCの表現へ変換
  2. 対応するCの関数を呼び出す
  3. 後処理: 返り値をCの表現からMLの表現へ
この、対応するCの関数 は idl の中で書かれた関数である。この対応する関数の 呼出をカスタマイズするのが quote(call,"..")である。

例 普通の呼出
unix.idlから拝借 unix.idlでの unlink
int unlink([string] char * filename);
スタブコード。これは普通に unlink を呼ぶ。
value camlidl_unix_unlink(
	value _v_filename)
{
  char *filename; /*in*/
  int _res;

  /* 前処理 caml から C へ */
  value _vres;
  filename = String_val(_v_filename);

  /* 呼出 */
  _res = unlink(filename);

  /* 後処理 C から caml へ*/
  _vres = Val_int(_res);
  return _vres;
}
例 quote(call,"..")をつかうもの
unix.idlから拝借 unix.idlで environment は以下のように書かれている。
[string*, null_terminated] char ** environment(void)
   quote(call, "_res = environ;");
environ は extern 宣言されている。どこで確保されてるんだろうねぇとおもって man environ を実行すると。あった。 おまけ
これは quote(call,"..") があるので、 environment 関数を呼ぶのではなく 結果に environ を入れる。スタブコードは以下のとおり。
value camlidl_unix_environment(value _unit)
{
  char **_res;
  mlsize_t _c1;
  mlsize_t _c2;
  value _v3;
  value _vres;

  /* begin user-supplied calling sequence */
_res = environ;
  /* end user-supplied calling sequence */
  _c1 = camlidl_ptrarray_size((void **) _res);
  _vres = camlidl_alloc(_c1, 0);
  Begin_root(_vres)
    for (_c2 = 0; _c2 < _c1; _c2++) {
      _v3 = copy_string(_res[_c2]);
      modify(&Field(_vres, _c2), _v3);
    }
  End_roots()
  return _vres;
}

なぞ (Ocaml内部で使われているマクロ? 関数??)

Begin_root(int)
End_roots()
camlidl_alloc_small(int,int)
Field(value,int) = .. (left value)
camlidl_find_enum

Int_val : MLのint → Cのint (value of int ってところ?)
Val_int: Cのint → MLのint

イメージ

 idl, MLから呼びたいCコード
         ↓
 ml, mli  型と external 宣言。実際どのCの関数と対応するか?
 *_stab.c MLのオブジェクトを C のオブジェクトに変換。
            関数呼出。
            返り値をMLのオブジェクトに戻す

 producer.cは提供したいライブラリ []で括られるものは producer.idl から
生成されるファイル

 consumer.ml → [producer.{ml,mli}] → [producer_stabs.c] → producer.c
            call               external call             

しばし内部を除き見する

compilerディレクトリに本体がある。依存性を見ると結構複雑。ファイルも多い。
Cのヘッダににているidlファイルを読んでいる場所はどこかな?
clflags.mlはスイッチになる変数がはいっているだけ
process_comp 内で処理。パターンマッチ
  Comp_typedecl, Comp_structdecl, Comp_uniondecl, Comp_enumdecl, Comp_fundecl, Comp_constdecl, Comp_diversion??, Comp_interface, Comp_import
File.component型である↑
パーザーは parse_aux.mlなど...
parser_midl.mly, lexer_midl.mll, linenum.mll はOcaml{Yacc,Lex}で自動生成した パーザーと字句解析器

予想

+--字句解析------+    +--構文木生成-----+    +--構文木生成-----+ 
| lexer_midl.mll | → | parser_midl.mly | → | parser_midl.mly | 
|                |    |                 |    |                 | 
+----------------+    +-----------------+    +-----------------+
parse.mlないで Parser_midl.fileを使用している
parse_auxってなんだ?

ocamlとともに

実際に使ってみる。まず、compilerディレクトリの中のファイルたちをまとめてバイト コードライブラリ (.cma) にしたい。そこで、こんな Makefileを書く。
> make bcl
成果物である files.cma を tests ディレクトリにもっていって、そこで遊ぶ。
例えば↓ -I でインターフェイスファイルのパス指定。
> ocaml -I /home/tak/download/camlidl-1.04/compiler/
        Objective Caml version 3.06

# #load "files.cma";;
# let input = open_in "arrays.idl";;
val input : in_channel = <abstr>
# let lb = Lexing.from_channel input ;;
val lb : Lexing.lexbuf =
 ...
# let res = Parser_midl.file Lexer_midl.token lb;;
val res : File.components =
  [File.Comp_fundecl
    {Funct.fun_name = "str1"; Funct.fun_mod = "";
     Funct.fun_res =
      Idltypes.Type_array
       ({Idltypes.bound = None; Idltypes.size = None; Idltypes.length = None;
         Idltypes.is_string = true; Idltypes.maybe_null = false;
         Idltypes.null_terminated = false},
       Idltypes.Type_int (Idltypes.Char, Idltypes.Iunboxed));
     Funct.fun_params =
      [("s", Funct.In,
       Idltypes.Type_array
  ...

使用例

上の説明とはまったくつながっていません。 libinn (The InterNetNews library) の parsedate を呼ぶスタブ。 ocamlmklib を用いてライブラリも作ってみました。
parsedate-2003-08-06.tar.gz

リンク

CamlIDL

作者: 増山隆 address
To Home
Valid html 4.0!