CritclはTclのソースにCなどのコードを埋め込んで、"on the fly"にコンパイルする拡張です。PerlでいうところのinlineCです。速くなると思います。ベンチマークも取ってみたいと思います。
#contents
***改造 [#gf70e472]
いまのとこ(critcl0.34)Windows+mingwではgccのコマンドパスの作成がちょっとおかしくてそのままだとコンパイルできないので、改造します。ていうか、空白パスをエスケープしたりするだけなんですが。単純にWindowsだとホームディレクトリへのパスに空白があるので、
 C:/Documents and Settings/MyAccount/.critcl   //FAIL
 C:/Documents\ and\ Settings/MyAccount/.critcl //OK
と適当に引っ掛かるところだけエスケープするだけです。面倒なので差分だけ置いておきます。
 4a5,8
 > proc escape {str} {
 >       return [string map {{ } {\ }} $str]
 > }
 >
 587c591
 <       lappend copts -I$cache
 ---
 >       lappend copts -I[escape $cache]
 600,601c604
 <
 <       set cmdline "$v::compile $copts -o $libfile $base.c $srcs"
 ---
 >       set cmdline "$v::compile $copts -o [escape $libfile] [escape $base.c]  $srcs"
他にも直すところがあるかもしれません。

***基本的な使い方 [#cfc70bd2]
-gccがインストールされていないといけません。
-コンパイルされたdll/soは~/.critclにキャッシュされます。

 package require critcl
 
 #整数を返す
 critcl::cproc add {int a int b} int {
     return a + b;
 }
 
 #実数を返す
 critcl::cproc addf {double a double b} double {
     return a + b;
 }
 
 #文字列を返す(長さは不変)
 critcl::cproc shiftc {char* c int len} char* {
 	int i;
 	for (i=0; i<len; i++) {
 		c[i] = c[i]+1;
 	}
 	return c;
 }
 
 #Tclオブジェクト
 critcl::cproc newtclobj {} Tcl_Obj* {
 	Tcl_Obj *obj = Tcl_NewStringObj("Hello World?", -1);
 	Tcl_IncrRefCount(obj);
 	return obj;
 }
 
 #Tclオブジェクト(リスト)
 critcl::cproc list_push {Tcl_Interp* interp Tcl_Obj* list Tcl_Obj* obj} ok {
 	if (Tcl_IsShared(list))
 		list = Tcl_DuplicateObj(list);
 	
 	Tcl_ListObjAppendElement(interp, list, obj);
 	
 	Tcl_SetObjResult(interp, list);
 	return TCL_OK;
 }

最後のやつみたいにリストや配列なんかの場合はSWIG使った方が楽な場面もあると思う。

***Cのヘッダファイルなどを埋め込み [#ca1838fd]
 package require critcl
 
 critcl::ccode {
 	#include <stdio.h>
 	#include <stdlib.h>
 }
 
 critcl::cproc testput {} void {
 	char *str = malloc(sizeof(char)*100);
 	int i;
 	for (i=0; i<100; i++) 
 		sprintf(str+i, "%d", i%10);
 	
 	for (i=0; i<10; i++) 
 		printf("%c\n", str[i]);
 	
 	free(str);
 	return;
 }

*** Cのファイルとリンク[#j1f0bbe8]
counter.h 
 #ifndef _DEF_H_COUNTER
 #define _DEF_H_COUNTER
 extern int incrCount();
 extern int CountVal;
 #endif

counter.c
 #include "counter.h"
 int CountVal = 0;
 int incrCount()
 {
 	return ++CountVal;
 }

test.tcl
 package require critcl
 
 critcl::cheaders counter.h
 critcl::csources counter.c
 
 critcl::ccode {
 	#include <stdio.h>
 	#include <stdlib.h>
 	#include "counter.h"
 }
 
 critcl::cproc countUp {} void {
 	int i;
 	for (i=0; i<10; i++) {
 		incrCount();
 		printf("%d\n", CountVal);
 	}
 	return;
 }

あと、ライブラリをリンクするときは
 critcl::clibraries file
というのでライブラリをリンクすることもできるようです。
みたいな。

***ライブラリの作成 [#xae0c10d]
critclではライブラリを作ることもできます。~
test.tcl
 package require critcl
 
 critcl::cproc add {int a int b} int {
     return a + b;    /* this is C code */
 }
 
 critcl::cproc addf {double a double b} double {
     return a + b;    /* this is C code */
 }

これをライブラリにするには、
 tclkit critcl.kit -lib test.tcl
とすると、test.dllが作成されます。これを使うには普通にtclshで
 load test.dll
などとしてやればいいです。Win,Mac,UNIXでMakefileを書き分けたりせずに簡単にコンパイルできるのが楽でいいと思いましたです。

***ライブラリの作成(パッケージ) [#d2731e91]
パッケージにすることもできます。~
cmath.tcl
 package require critcl
 
 package provide cmath 1.0
 
 namespace eval cmath {
 	critcl::cproc add {int a int b} int {
 	    return a + b;    /* this is C code */
 	}
 	
 	critcl::cproc addf {double a double b} double {
 	    return a + b;    /* this is C code */
 	}
 }

 tclkit critcl.kit -pkg test.tcl

libディレクトリ以下にパッケージを作ります。
~
lib以下にはターゲットマシンごとのライブラリが存在します。が、特定のプラットフォーム決め撃ちの時はpkgIndex.tclに次のように書いておけばpkgIndex.tclとライブラリの二つのファイルだけでいけます。
 package ifneeded cmath 1.0 " 
 	package provide cmath 1.0; 
 	[list load [file join $dir cmath.dll] cmath]; 
 "
***C++も使えるみたい [#l24b9fac]
C++を使う場合は次のようにする。
 package require critcl
 critcl::config language c++
 critcl::clibraries -lstdc++

***いろいろなオプションとか [#d079a15b]
 critcl::config I            # -Iオプション
 critcl::config L            # -Lオプション
 critcl::config appinit      # ?
 critcl::config combine      # ?
 critcl::config force        # 強制的に再コンパイルする
 critcl::config keepsrc      # ソースファイルを出力
 critcl::config language     # 言語指定(-x)
 critcl::config lines        # ?
 critcl::config outdir       # 出力ディレクトリ?
 critcl::config tk           # ?






***ベンチマーク(たらいまわし) [#r4656001]
 source critcl.kit
 package require critcl
 
 proc tcl_tak {x y z} {
 	if {$x <= $y} {return $z}
 	return [tcl_tak \
 		[tcl_tak [expr $x-1] $y $z] \
 		[tcl_tak [expr $y-1] $z $x] \
 		[tcl_tak [expr $z-1] $x $y] \
 	]
 }
 
 critcl::ccode {
 	static int tak (int x, int y, int z)
 	{
 		if (x<=y) return z;
 		return tak(
 			tak(x-1, y, z),
 			tak(y-1, z, x),
 			tak(z-1, x, y)
 		);
 	}
 }
 
 critcl::cproc c_tak {int x int y int z} int {
 	return tak(x,y,z);
 }
 
 set x 20
 set y 10
 set z 5
 puts "Tcl [time {tcl_tak $x $y $z} 10]"
 puts "C   [time {c_tak $x $y $z} 10]"

一回目
 Tcl 1614874 microseconds per iteration
 C   93094 microseconds per iteration
二回目
 Tcl 1612537 microseconds per iteration
 C   3317 microseconds per iteration

注:一回目はCのコードをコンパイルするので遅いです。

***リンク [#x6a741b5]
-http://www.equi4.com/critcl.html
http://wiki.tcl.tk/11593

***コメントをどーぞ [#v624aabe]
#comment

----
[[CategoryTclTk]]

|New|Edit|Diff|History|Attach|Copy|Rename|
HTML convert time: 0.006 sec.