体験!マイコンボードで組込みLinux

第12回 tcl-Cの連携とtcl,Luaからのハードウェアアクセス

この記事を読むのに必要な時間:およそ 12.5 分

tcl言語とC言語の連携

tcl言語でC言語の関数を使う

tcl言語はプラットフォームを問わず幅広く使われている言語です。今回は,tcl言語からC言語の関数を呼び出す方法について解説します。

tcl言語は高水準のインタープリタなので,柔軟にプログラム開発や試作などを手軽にオンボードで行うことができます。一方,C言語では低水準プログラミングに対応しており,かつ,ライブラリも完備しているので,Linuxの全ての機能を使ったり,ハードウェアの直接アクセスを行ったりすることができます。組込みボードでは低水準のハードウェアアクセスの部分のみをC言語の関数にまとめて,それ以外の高水準のプログラミングをtcl言語で行うのが最適だと思われます。

ここではC言語で簡単な演算を行う関数を作成し,それを共有ライブラリとしてコンパイルをして,tcl言語のスクリプトからC言語で書かれた自作共有ライブラリを呼び出すことをやってみます。

tcl言語から呼び出すC言語関数

全ての引数の数と累積加算の戻り値を返すC言語側の関数は,リスト1のようになります。

tcl言語から呼び出されるC言語で書かれた自作共有ライブラリ内での関数の戻り値は,正常終了を示すTCL_OKとエラー発生を示すTCL_ERRORのいずれかを指定します。tcl言語から呼び出されるC言語で書かれた自作共有ライブラリでは,初期化関数において,tcl言語から呼び出されるC言語の関数を登録します。

初期化関数名は以下となります。

int [任意の名称]_Init(Tcl_Interp *interp)

任意の名称は必ずしも共有ライブラリ名と一致させる必要はなく,tcl言語のスクリプトで共有ライブラリを呼び出すときに,共有ライブラリのパスとともに任意の名称を併せて指定をします。

tcl言語から呼び出されるC言語の関数の仕様は,旧仕様と新仕様の2つが併存しますが,現状のSH7706LSR上では新仕様の関数は動作するものの安定さに欠けるので,ここではSH7706LSRで安定動作をする旧仕様で関数を作成します。

リスト1

01:  #include <tcl.h>
02:  
03:  int CalcCmd(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv);
04:  
05:  int Calc_Init(Tcl_Interp *interp) {
06:  Tcl_CreateCommand(interp, "calc", CalcCmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
07:      Tcl_PkgProvide(interp, "calc", "1.1");
08:      return TCL_OK;
09:  }
10:  
11:  int CalcCmd(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv) {
12:      int    data, i, n, error;
13:  
14:      if(argc <= 2) {
15:          interp->result = "Usage: calc num num ...";
16:          return TCL_ERROR;
17:      }
18:      data = 0;
19:      for(i = 1;i < argc;i++) {
20:          error = Tcl_GetInt(interp, argv[i], &n);
21:          if(error != TCL_OK) return error;
22:          data += n;
23:      }
24:      sprintf(interp->result, "%d", data);
25:      return TCL_OK;
26:  }

tcl言語から呼び出されるC言語の関数を記述する場合は,tcl言語インターフェースのためのヘッダが必要になります。これはリスト1の1行目のようになります。

また,C言語側での関数名はtcl言語から呼び出す関数名である必要はなく,初期化関数においてtcl言語から呼び出す関数名を指定するので,適当なわかりやすい関数名にしておきます。

自作共有ライブラリ内での初期化関数やtcl言語から呼び出されるC言語の関数とtcl言語インタープリタ処理系とのインターフェースは,tcl言語インタープリタ処理系内部のポインタであるTcl_Interp型のポインタを介して行います。

初期化関数においては,tcl言語から呼び出されるC言語の関数の生成とtcl言語から呼び出されるC言語の関数の登録を行います。

tcl言語から呼び出されるC言語の関数の生成は,Tcl_CreateCommand関数(リスト1の6行目)で行い,第1引数ではTcl_Interp型のポインタ,第2引数ではtcl言語から呼び出す関数名,第3引数ではtcl言語から呼び出されるC言語での関数名を指定し,これらの3つの引数は必須となります。オプションとしては第4引数では固有値,第5引数ではコマンド削除時に呼び出される終了処理のためのC言語での関数名です。通常,第4引数での固有値は不要ですが,複数のtcl言語の関数で同じC言語の関数を共有させる場合は,tcl言語の関数の判別に固有値を使います。

tcl言語から呼び出されるC言語の関数の登録は,PkgProvide関数(リスト1の7行目)で行い,第1引数ではTcl_Interp型のポインタ,第2引数ではtcl言語から呼び出す関数名,第3引数ではバージョンを指定しますが,特に必要がなければ適当な値にしておきます。

tcl言語から呼び出されるC言語の関数であるCalcCmd関数(リスト1の11~26行目)では,第1引数では固有値,第2引数ではTcl_Interp型のポインタ,第3引数ではtcl言語関数での引数の数,第4引数では引数本体を受け取ります。

tcl言語から呼び出されるC言語の関数内で数値などの引数の実体を取得するには,引数本体だけでなくTcl_Interp型のポインタと併用しなければならず,数値を取得するにはTcl_GetInt関数(リスト1の20行目)で行います。

C言語での戻り値は TCL_OK または TCL_ERROR のいずれかなので,tcl言語から見た戻り値はTcl_Interp型の resultメンバに文字列ポインタを代入し(リスト1の15行目)⁠数値の場合であっても数値の文字列に変換して文字列として代入をします(リスト1の24行目)⁠

著者プロフィール

みついわゆきお

1986年日立製作所入所,その3年後に自社ワークステーションでの開発業務をきっかけにBSDを経てLinux利用を始める。

1991年日立を退社し,その後,ボランティアでLinux関連ツールの整備と開発しながらWindows否定運動およびLinux普及運動を開始し,Linuxディストリビューション草創期にはPlamoLinuxのメンテナンスにもかかわる。

2001年ごろより非営利ベースでボードコンピュータの開発を開始し,やがて,無償によりハードとソフトを開発したH8マイコンボードの販売を秋月電子にて開始した。

現在,ボードコンピュータ用基本ソフトMES2.5や,SHプロセッサ向けLinuxパッチおよびTOPPERS/JSPパッチを無償で一般に提供しながら,ティーエーシーやエムイーシステムより原価率100%を目標(ただし,販売店の営業・販売費用や開発・製造の際の差損を除く)としたSuperHボードコンピュータを販売中。

また,現在でも頑固にMS社否定及びWindows撲滅運動に邁進中。

コメント

コメントの記入