SWIGでTCL
をテンプレートにして作成
[
Front page
] [
Page list
|
Search
|
Recent changes
|
RSS of recent changes
]
Start:
***その1
SWIGのタイプマップについて調べているのですが、Tclのコマン...
%sum { 1 2 3 4 5}
1 2 3 4 5 = 15
と、このようにリストの値を合計するようなコマンドを作りた...
void sum(int list[], int len) {
int i;
int sum=0;
for (i=0; i<len; i++){
sum += list[i];
printf("%d ", list[i]);
}
printf("= %d\n", sum);
}
で、インターフェースファイル test.i はこんな感じになります
%module test
%typemap(in) (int list[], int len) {
int i;
Tcl_Obj *tclobj=NULL;
/*リストオブジェクトの長さの取得*/
if(Tcl_ListObjLength(interp, $input, &$2)==TCL_ERRO...
return TCL_ERROR;
}
/*リストオブジェクトを新しいint配列に変換*/
$1 = (int*) malloc($2 * sizeof(int));
for(i=0; i<$2; i++) {
Tcl_ListObjIndex(interp, $input, i, &tclobj);
Tcl_GetIntFromObj(interp, tclobj, $1+i);
}
}
%typemap(freearg) (int list[], int len) {
if ($1) free($1);
}
extern void sum(int list[], int len);
%typemap(in) (int list[], int len)でCのsum関数に対応した...
%load test
%sum { 1 2 3 4 5}
1 2 3 4 5 = 15
% sum 1
1 = 1
まあ、こんなもんでしょうかね・・・。それじゃあ・・・
% sum 1 2
Wrong # args.:sum list ?len? argument 2
% sum {1 2 a}
1 2 1735289204 = 1735289207
expected integer but got "a"
% sum a
0 = 0
expected integer but got "a"
引数は1つしか取らないのでエラーになるのはいいんですが、?l...
***その2
タイプマップで複数の引数を取る時のwrong argsのエラーメッ...
test.c
int add(int a, int b) {
return a+b;
}
test.i
%module test
%typemap(default) int b {
$1 = 0;
}
extern int add(int a, int b);
typemap(default)というのは、デフォルト値を設定するという...
% load test
% add
Wrong # args. :add a ?b? argument 1
% add 1 2
3
% add 1
1
% add a
expected integer but got "a":add a ?b? argument 1
%
うーん、問題がないようだ。ちゃんと省略できてるし、エラー...
***その3
省略可能引数についてまだやります。引数が多い時はどうなる...
test.c
int add(int a, int b, int c) {
return a+b+c;
}
test.i
%module test
%typemap(default) int b {
$1 = 0;
}
extern int add(int a, int b, int c);
コード生成もコンパイルも通るようです・・・。では実行をは...
% load test
% add
Wrong # args. :add a ?b? ?c? argument 1
% add 1
8994641
% add 1 2
8994643
% add 1 2 3
6
うーん・・・なるほど・・・。まあ当然なんですが・・・。ラ...
***その4
複数の引数をタイプマップで変換したときの引数のエラーメッ...
***その5(C++)
引数の省略の問題はまあさておき。。。C++のクラスをTkのよ...
test.h
#ifndef DEF_TEST
#define DEF_TEST
class Test {
private:
int z;
public:
Test();
~Test();
int x;
int y;
int Add();
int getZ();
void setZ(int num);
};
#endif
test.cpp
#include "test.h"
#include <stdio.h>
Test::Test() {
printf("born\n");
}
Test::~Test() {
printf("killed\n");
}
int Test::Add(){
return x + y;
}
int Test::getZ(){
return z;
}
void Test::setZ (int num){
z=num;
}
test.i
%module test
%{
#include "test.h"
%}
%include "test.h"
これをコンパイルして実行してみます。c++の時は-c++オプショ...
swing -c++ -tcl test.i
みたいにします。
% load test
% Test t
born
_a84bca00_p_Test
% t configure -x 3
% t configure -y 4
% t configure -z 5
Invalid attribute name.
% t configure -x 6 -y 7
% t cget -x
6
% t cget -y
7
% t cget -z
Invalid attribute name.
どうやらちゃんとプライベートなメンバにはアクセスできない...
% t m
Invalid method. Must be one of: configure cget -acquire ...
メソッド名を間違えた時も、ちゃんとアクセス可能なメソッド...
% t setZ 8
% t getZ
8
% t configure -x 9 -y 10
% t Add
19
普通だ・・・。普通すぎて何も書くことが無い・・・。
***その6(メモリ管理)
SWIGのマニュアルの23.4.2章のメモリ管理のところに具体例つ...
% t cget -thisown
1
で調べられます。Tclからだけ参照されていれば所有権があると...
-acquire 所有権を得る。
-disown 所有権を失う。
-delete クラスの破棄。
で、-deleteをするとデストラクタが呼ばれて破棄されます。所...
***その7(名前空間)
tclの拡張はパッケージ化して名前空間でコマンドがまとめられ...
test.c
int add(int a, int b) {
return a+b;
}
int sub(int a, int b) {
return a-b;
}
test.i
%module test
extern int add(int a, int b);
extern int sub(int a, int b);
パッケージのバージョンはswigでラッパーコードを作成する時...
swig -tcl -pkgversion 1.0 -namespace test.i
とまあ、こんな感じです。namespaceはデフォルトではインター...
コンパイルしてパッケージ化してみます。tclshでパッケージの...
% pkg_mkIndex . test.dll
これでpkgIndex.tclが作られます。パッケージのインストール...
% lappend auto_path .
C:/Tcl/lib/tcl8.4 C:/Tcl/lib .
% package require test
1.0
無事にパッケージが読み込めたみたいです。では使ってみます。
% test::add 1 2
3
% test::sub 3 4
-1
% test::add
Wrong # args. :test::adda b argument 1
% test::sub
Wrong # args. :test::suba b argument 1
エラーメッセージがおかしいです。test::add a bなんじゃ・・...
% namespace import test::*
% add 1 2
invalid command name "add"
ありゃ・・・。test_wrap.cを確認してみたらTcl_Exprtしてな...
***その8(namespaceのインポート)
namespace のインポートが出来ないのが腹立たしいのでパッチ...
--- original_tcl8.swg Fri Dec 12 18:29:00 2003
+++ tcl8.swg Thu Feb 26 19:40:51 2004
@@ -607,6 +607,9 @@
SWIGEXPORT(int) SWIG_init(Tcl_Interp *interp) {
int i;
static int _init = 0;
+#ifdef SWIG_namespace
+ Tcl_Namespace *nsPtr;
+#endif
if (interp == 0) return TCL_ERROR;
#ifdef USE_TCL_STUBS
if (Tcl_InitStubs(interp, (char*)"8.1", 0) == NULL) {
@@ -625,13 +628,26 @@
}
_init = 1;
}
+
+#ifdef SWIG_namespace
+ nsPtr = (Tcl_Namespace *)Tcl_FindNamespace(interp, SWI...
+ (Tcl_Namespace *)NULL, TCL_LEAVE_ERR_MSG);
+ if (nsPtr == NULL) return TCL_ERROR;
+#endif
+
for (i = 0; swig_commands[i].name; i++) {
Tcl_CreateObjCommand(interp, (char *) swig_comman...
+#ifdef SWIG_namespace
+ Tcl_Export(interp, nsPtr, (char *)( swig_commands...
+#endif
}
for (i = 0; swig_variables[i].name; i++) {
Tcl_SetVar(interp, (char *) swig_variables[i].nam...
Tcl_TraceVar(interp, (char *) swig_variables[i].n...
Tcl_TraceVar(interp, (char *) swig_variables[i].n...
+#ifdef SWIG_namespace
+ Tcl_Export(interp, nsPtr, (char *)( swig_variable...
+#endif
}
SWIG_InstallConstants(interp, swig_constants);
%}
それでは前にnamespace のところで作ったやつで試してみます。
% load test
% test::add
Wrong # args. :test::adda b argument 1
% test::add 1 2
3
% test::sub 1 2
-1
まあ、ここまでは動きます。namespaceをインポートしてみます...
% namespace import test::a*
% add
Wrong # args. :test::adda b argument 1
% sub
wrong # args: should be "subst ?-nobackslashes? ?-nocomm...
% add 2 3
5
test::a*だけインポートしたので、addコマンドだけインポート...
***その9(タイプマップ)
まだやります。タイプマップファイルを眺めていると、typemap...
test.c
int sum(int list[], int len) {
int i;
int sum=0;
for (i=0; i<len; i++){
sum += list[i];
printf("%d ", list[i]);
}
printf("= %d\n", sum);
return 0;
}
これは前に使ったやつと同じなんですが、前は
%typemap (int list[], int len)
みたいなタイプマップを書きましたが、今回はタイプマップの...
test.i
%module test
%wrapper %{
int *LEN;
%}
%typemap(in,numinputs=0) int len {
LEN = &$1;
}
%typemap(in,numinputs=1) int list[] {
int i;
Tcl_Obj *tclobj=NULL;
/*リストオブジェクトの長さの取得*/
if(Tcl_ListObjLength(interp, $input, LEN)==TCL_ERRO...
return TCL_ERROR;
}
/*リストオブジェクトを新しいint配列に変換*/
$1 = (int*) malloc(*LEN * sizeof(int));
for(i=0; i<*LEN; i++) {
Tcl_ListObjIndex(interp, $input, i, &tclobj);
Tcl_GetIntFromObj(interp, tclobj, $1+i);
}
}
%typemap(freearg) int list[] {
if ($1) free($1);
}
extern int sum(int list[], int len);
とまあこんな感じ・・・。引数ごとに処理するスコープで共有...
% load test
% sum
Wrong # args. :sum list argument 1
% sum {1 2 3 4 5}
1 2 3 4 5 = 15
0
エラーメッセージの引数がちゃんと省略されています(目的達...
***その10(例外処理)
例外処理とかのやり方を考えます。%exceptionを使うと、関数...
test.c
int mydiv(int a, int b, int *out) {
if (b==0) return 1;
*out = a/b;
return 0;
}
0で除算するとエラーコード1を返す関数です。
test.i
%module test
%typemap(in, numinputs=0) int *OUTPUT(int temp) {
$1 = &temp; /*実体の確保*/
}
%typemap(argout) int *OUTPUT {
Tcl_SetObjResult(interp,Tcl_NewIntObj((int) *$1));
}
%exception mydiv %{
$action
switch (result) {
case 0: /* OK */
break;
case 1: /* ErrorCode 1 */
Tcl_SetResult(interp, "Divide by Zero!!", T...
SWIG_fail;
default: /* Unknown Error */
Tcl_SetResult(interp, "Unknown Error!!", TC...
SWIG_fail;
}
%}
extern int mydiv(int a, int b, int *OUTPUT);
このインターフェースでは*OUTPUTが2つと、例外処理をしてる...
% load test
% mydiv
Wrong # args. :mydiv a b argument 1
% mydiv 1 0
Divide by Zero!!
% mydiv 1 1
1
と、まあ、エラーの時は値のかわりにエラーメッセージが表示...
% if {[catch {mydiv 1 0} msg]} {puts "ERROR $msg"} else ...
ERROR Divide by Zero!!
% if {[catch {mydiv 1 1} msg]} {puts "ERROR $msg"} else ...
1
と、まあちゃんとエラーもキャッチできるようになりました。...
----
[[CategoryTclTk]] [[CategorySWIG]]
End:
***その1
SWIGのタイプマップについて調べているのですが、Tclのコマン...
%sum { 1 2 3 4 5}
1 2 3 4 5 = 15
と、このようにリストの値を合計するようなコマンドを作りた...
void sum(int list[], int len) {
int i;
int sum=0;
for (i=0; i<len; i++){
sum += list[i];
printf("%d ", list[i]);
}
printf("= %d\n", sum);
}
で、インターフェースファイル test.i はこんな感じになります
%module test
%typemap(in) (int list[], int len) {
int i;
Tcl_Obj *tclobj=NULL;
/*リストオブジェクトの長さの取得*/
if(Tcl_ListObjLength(interp, $input, &$2)==TCL_ERRO...
return TCL_ERROR;
}
/*リストオブジェクトを新しいint配列に変換*/
$1 = (int*) malloc($2 * sizeof(int));
for(i=0; i<$2; i++) {
Tcl_ListObjIndex(interp, $input, i, &tclobj);
Tcl_GetIntFromObj(interp, tclobj, $1+i);
}
}
%typemap(freearg) (int list[], int len) {
if ($1) free($1);
}
extern void sum(int list[], int len);
%typemap(in) (int list[], int len)でCのsum関数に対応した...
%load test
%sum { 1 2 3 4 5}
1 2 3 4 5 = 15
% sum 1
1 = 1
まあ、こんなもんでしょうかね・・・。それじゃあ・・・
% sum 1 2
Wrong # args.:sum list ?len? argument 2
% sum {1 2 a}
1 2 1735289204 = 1735289207
expected integer but got "a"
% sum a
0 = 0
expected integer but got "a"
引数は1つしか取らないのでエラーになるのはいいんですが、?l...
***その2
タイプマップで複数の引数を取る時のwrong argsのエラーメッ...
test.c
int add(int a, int b) {
return a+b;
}
test.i
%module test
%typemap(default) int b {
$1 = 0;
}
extern int add(int a, int b);
typemap(default)というのは、デフォルト値を設定するという...
% load test
% add
Wrong # args. :add a ?b? argument 1
% add 1 2
3
% add 1
1
% add a
expected integer but got "a":add a ?b? argument 1
%
うーん、問題がないようだ。ちゃんと省略できてるし、エラー...
***その3
省略可能引数についてまだやります。引数が多い時はどうなる...
test.c
int add(int a, int b, int c) {
return a+b+c;
}
test.i
%module test
%typemap(default) int b {
$1 = 0;
}
extern int add(int a, int b, int c);
コード生成もコンパイルも通るようです・・・。では実行をは...
% load test
% add
Wrong # args. :add a ?b? ?c? argument 1
% add 1
8994641
% add 1 2
8994643
% add 1 2 3
6
うーん・・・なるほど・・・。まあ当然なんですが・・・。ラ...
***その4
複数の引数をタイプマップで変換したときの引数のエラーメッ...
***その5(C++)
引数の省略の問題はまあさておき。。。C++のクラスをTkのよ...
test.h
#ifndef DEF_TEST
#define DEF_TEST
class Test {
private:
int z;
public:
Test();
~Test();
int x;
int y;
int Add();
int getZ();
void setZ(int num);
};
#endif
test.cpp
#include "test.h"
#include <stdio.h>
Test::Test() {
printf("born\n");
}
Test::~Test() {
printf("killed\n");
}
int Test::Add(){
return x + y;
}
int Test::getZ(){
return z;
}
void Test::setZ (int num){
z=num;
}
test.i
%module test
%{
#include "test.h"
%}
%include "test.h"
これをコンパイルして実行してみます。c++の時は-c++オプショ...
swing -c++ -tcl test.i
みたいにします。
% load test
% Test t
born
_a84bca00_p_Test
% t configure -x 3
% t configure -y 4
% t configure -z 5
Invalid attribute name.
% t configure -x 6 -y 7
% t cget -x
6
% t cget -y
7
% t cget -z
Invalid attribute name.
どうやらちゃんとプライベートなメンバにはアクセスできない...
% t m
Invalid method. Must be one of: configure cget -acquire ...
メソッド名を間違えた時も、ちゃんとアクセス可能なメソッド...
% t setZ 8
% t getZ
8
% t configure -x 9 -y 10
% t Add
19
普通だ・・・。普通すぎて何も書くことが無い・・・。
***その6(メモリ管理)
SWIGのマニュアルの23.4.2章のメモリ管理のところに具体例つ...
% t cget -thisown
1
で調べられます。Tclからだけ参照されていれば所有権があると...
-acquire 所有権を得る。
-disown 所有権を失う。
-delete クラスの破棄。
で、-deleteをするとデストラクタが呼ばれて破棄されます。所...
***その7(名前空間)
tclの拡張はパッケージ化して名前空間でコマンドがまとめられ...
test.c
int add(int a, int b) {
return a+b;
}
int sub(int a, int b) {
return a-b;
}
test.i
%module test
extern int add(int a, int b);
extern int sub(int a, int b);
パッケージのバージョンはswigでラッパーコードを作成する時...
swig -tcl -pkgversion 1.0 -namespace test.i
とまあ、こんな感じです。namespaceはデフォルトではインター...
コンパイルしてパッケージ化してみます。tclshでパッケージの...
% pkg_mkIndex . test.dll
これでpkgIndex.tclが作られます。パッケージのインストール...
% lappend auto_path .
C:/Tcl/lib/tcl8.4 C:/Tcl/lib .
% package require test
1.0
無事にパッケージが読み込めたみたいです。では使ってみます。
% test::add 1 2
3
% test::sub 3 4
-1
% test::add
Wrong # args. :test::adda b argument 1
% test::sub
Wrong # args. :test::suba b argument 1
エラーメッセージがおかしいです。test::add a bなんじゃ・・...
% namespace import test::*
% add 1 2
invalid command name "add"
ありゃ・・・。test_wrap.cを確認してみたらTcl_Exprtしてな...
***その8(namespaceのインポート)
namespace のインポートが出来ないのが腹立たしいのでパッチ...
--- original_tcl8.swg Fri Dec 12 18:29:00 2003
+++ tcl8.swg Thu Feb 26 19:40:51 2004
@@ -607,6 +607,9 @@
SWIGEXPORT(int) SWIG_init(Tcl_Interp *interp) {
int i;
static int _init = 0;
+#ifdef SWIG_namespace
+ Tcl_Namespace *nsPtr;
+#endif
if (interp == 0) return TCL_ERROR;
#ifdef USE_TCL_STUBS
if (Tcl_InitStubs(interp, (char*)"8.1", 0) == NULL) {
@@ -625,13 +628,26 @@
}
_init = 1;
}
+
+#ifdef SWIG_namespace
+ nsPtr = (Tcl_Namespace *)Tcl_FindNamespace(interp, SWI...
+ (Tcl_Namespace *)NULL, TCL_LEAVE_ERR_MSG);
+ if (nsPtr == NULL) return TCL_ERROR;
+#endif
+
for (i = 0; swig_commands[i].name; i++) {
Tcl_CreateObjCommand(interp, (char *) swig_comman...
+#ifdef SWIG_namespace
+ Tcl_Export(interp, nsPtr, (char *)( swig_commands...
+#endif
}
for (i = 0; swig_variables[i].name; i++) {
Tcl_SetVar(interp, (char *) swig_variables[i].nam...
Tcl_TraceVar(interp, (char *) swig_variables[i].n...
Tcl_TraceVar(interp, (char *) swig_variables[i].n...
+#ifdef SWIG_namespace
+ Tcl_Export(interp, nsPtr, (char *)( swig_variable...
+#endif
}
SWIG_InstallConstants(interp, swig_constants);
%}
それでは前にnamespace のところで作ったやつで試してみます。
% load test
% test::add
Wrong # args. :test::adda b argument 1
% test::add 1 2
3
% test::sub 1 2
-1
まあ、ここまでは動きます。namespaceをインポートしてみます...
% namespace import test::a*
% add
Wrong # args. :test::adda b argument 1
% sub
wrong # args: should be "subst ?-nobackslashes? ?-nocomm...
% add 2 3
5
test::a*だけインポートしたので、addコマンドだけインポート...
***その9(タイプマップ)
まだやります。タイプマップファイルを眺めていると、typemap...
test.c
int sum(int list[], int len) {
int i;
int sum=0;
for (i=0; i<len; i++){
sum += list[i];
printf("%d ", list[i]);
}
printf("= %d\n", sum);
return 0;
}
これは前に使ったやつと同じなんですが、前は
%typemap (int list[], int len)
みたいなタイプマップを書きましたが、今回はタイプマップの...
test.i
%module test
%wrapper %{
int *LEN;
%}
%typemap(in,numinputs=0) int len {
LEN = &$1;
}
%typemap(in,numinputs=1) int list[] {
int i;
Tcl_Obj *tclobj=NULL;
/*リストオブジェクトの長さの取得*/
if(Tcl_ListObjLength(interp, $input, LEN)==TCL_ERRO...
return TCL_ERROR;
}
/*リストオブジェクトを新しいint配列に変換*/
$1 = (int*) malloc(*LEN * sizeof(int));
for(i=0; i<*LEN; i++) {
Tcl_ListObjIndex(interp, $input, i, &tclobj);
Tcl_GetIntFromObj(interp, tclobj, $1+i);
}
}
%typemap(freearg) int list[] {
if ($1) free($1);
}
extern int sum(int list[], int len);
とまあこんな感じ・・・。引数ごとに処理するスコープで共有...
% load test
% sum
Wrong # args. :sum list argument 1
% sum {1 2 3 4 5}
1 2 3 4 5 = 15
0
エラーメッセージの引数がちゃんと省略されています(目的達...
***その10(例外処理)
例外処理とかのやり方を考えます。%exceptionを使うと、関数...
test.c
int mydiv(int a, int b, int *out) {
if (b==0) return 1;
*out = a/b;
return 0;
}
0で除算するとエラーコード1を返す関数です。
test.i
%module test
%typemap(in, numinputs=0) int *OUTPUT(int temp) {
$1 = &temp; /*実体の確保*/
}
%typemap(argout) int *OUTPUT {
Tcl_SetObjResult(interp,Tcl_NewIntObj((int) *$1));
}
%exception mydiv %{
$action
switch (result) {
case 0: /* OK */
break;
case 1: /* ErrorCode 1 */
Tcl_SetResult(interp, "Divide by Zero!!", T...
SWIG_fail;
default: /* Unknown Error */
Tcl_SetResult(interp, "Unknown Error!!", TC...
SWIG_fail;
}
%}
extern int mydiv(int a, int b, int *OUTPUT);
このインターフェースでは*OUTPUTが2つと、例外処理をしてる...
% load test
% mydiv
Wrong # args. :mydiv a b argument 1
% mydiv 1 0
Divide by Zero!!
% mydiv 1 1
1
と、まあ、エラーの時は値のかわりにエラーメッセージが表示...
% if {[catch {mydiv 1 0} msg]} {puts "ERROR $msg"} else ...
ERROR Divide by Zero!!
% if {[catch {mydiv 1 1} msg]} {puts "ERROR $msg"} else ...
1
と、まあちゃんとエラーもキャッチできるようになりました。...
----
[[CategoryTclTk]] [[CategorySWIG]]
Page:
HTML convert time: 0.006 sec.