Source code is now at http://www.equi4.com/critlib/ - JCW
It is not clear, after reading this page, exactly what files have to be installed on a Windows machine to use CriTcl. Does one have to install the critcl source code and then some other piece(s)?
June 2002 - Yes, you need critcl installed as a normal Tcl package (i.e. so "package require critcl" works in tclsh or tclkit) and you need to set things up so "gcc" works. What I do is install the mingw system, and set up the PATH so "gcc" works from the command line. That's it. -jcw
See also Richard Suchenwirth's C code generators page.
The C Runtime In Tcl is a self-contained package to build C code into an extension on the fly. It is somewhat inspired by Brian Ingerson's Inline for Perl, but CriTcl is considerably more lightweight. [While Python also has an Inline [L1 ], it apparently has no direct genetic connection to CriTcl.]
The idea is to wrap C code into something that will compile into a Tcl extension, and then also fire up the compiler. Compiled chunks will be cached in your ~/.critcl/ directory, so subsequent use will be instant.
The main definition is "critcl::cproc", which lets you define a (surprise) C proc, with C code as body. Args and return values must be typed. There are no default args or ways to pass more sophisticated data items than int/long/float/double/char* for now.
There is also a "critcl::ccode" call, to inject C code as is, and a "ccommand" call, which ties code to the Tcl_CreateObjCommand without further wrapping.
The use of Tcl stubs, and the fact that this extension has all include files it needs to make compilation self-contained, means that this is a pure Tcl package, which should work with any (8.1 and up) installation of Tcl. Most importantly, CriTcl does not care a bit where Tcl was installed, nor even whether it was built as a static or as a dynamic executable.
This is a working demo, but it is still young. It will for now blindly use "gcc" to do the compile and has somewhat rudimentary error handling. CriTcl has been verified to work on Linux and Win NT4 (MinGW) so far.
Works on Win98 with mingw. IDG
Oh, one more thing: this code assumes the md5 command is available.
There's a new CritLib package with several extensions (blowfish, hexdump, ihash, lazy, lzrw1, md5c, mvector, noop, rchan, zlib) - see http://www.equi4.com/critlib/
Source:
package require critcl namespace import critcl::* cproc noop {} void {} cproc add {int x int y} int { return x + y; } cproc cube {int x} int { return x * x * x; } puts "add 123 456 : [add 123 456]" catch {add 1} err; puts "add 1 : $err" catch {add 1 2 3} err; puts "add 1 2 3 : $err" catch {add 0 zero} err; puts "add 0 zero : $err" proc sum {a b} { return [expr {$a+$b}] } proc pow3 {a} { return [expr {$a*$a*$a}] } proc ntimes {n cmd t} { set on $n set r {} while {[incr n -1] >= 0} { lappend r $cmd } set v [uplevel 1 [list time [join $r {; }] $t]] return [lreplace $v 0 0 [expr {[lindex $v 0]/(1.0*$on)}]] } puts "" puts "Tcl noop: [ntimes 100 {} 1000]" puts " C noop: [ntimes 100 {noop} 1000]" set a 1 set b 2 puts "" puts "Tcl expr: [ntimes 100 {expr {1+2}} 1000]" puts "Tcl vars: [ntimes 100 {expr {$a+$b}} 1000]" puts "Tcl sum: [ntimes 100 {sum 1 2} 1000]" puts " C add: [ntimes 100 {add 1 2} 1000]" puts " C vars: [ntimes 100 {add $a $b} 1000]" puts "" puts "Tcl expr: [ntimes 100 {expr {2*2*2}} 1000]" puts "Tcl vars: [ntimes 100 {expr {$b*$b*$b}} 1000]" puts "Tcl pow3: [ntimes 100 {pow3 2} 1000]" puts " C cube: [ntimes 100 {cube 2} 1000]" puts " C vars: [ntimes 100 {cube $b} 1000]"
Output (SuSE 7.1 Linux, PIII/650):
add 123 456 : 579 add 1 : wrong # args: should be "add x y" add 1 2 3 : wrong # args: should be "add x y" add 0 zero : expected integer but got "zero" Tcl noop: 0.01 microseconds per iteration C noop: 0.67 microseconds per iteration Tcl expr: 0.36 microseconds per iteration Tcl vars: 1.92 microseconds per iteration Tcl sum: 2.51 microseconds per iteration C add: 1.06 microseconds per iteration C vars: 2.66 microseconds per iteration Tcl expr: 0.7 microseconds per iteration Tcl vars: 2.83 microseconds per iteration Tcl pow3: 2.78 microseconds per iteration C cube: 0.96 microseconds per iteration C vars: 1.81 microseconds per iteration
AK Ideas
I don't follow most of the AK ideas above. My impression was that the reason for the "no compiled code" rule in tcllib was because we did not want to require a compiler on the user's machine in order for the user to use all of tcllib. There's nothing here that provides a compiler, so I don't see how the nifty features provided by CriTcl change anything about whether or not to include C-coded packages in tcllib.
DGP
(Please read the above as "AK's ideas", not mine)
I am not sure that extending CriTcl to create a build system of some sort would be my first goal. The model I have is a group of developers, all fed up with build issues (and with a standard C compiler within reach at all times), and the rest of the world (trying to never have to find out what a "compiler" is, let alone allow one on their machine). In this context, CriTcl is way cool for developers IMO, yet useless for the majority of people on this planet.
For deployment, I always use TclKit. Once CriTcl gains the capability to build all C packages into either a shared or a static lib, it will be helpful for any developer with the same type of machine as their clients to press a button, wrap all C code up, package the app into some standalone system (not necessarily TclKit of course), and never look back.
From where I stand, the best delivery mode to developers is source code (unless it's so standard that a binary is more convenient and is supplied by a trusted source), while the best deployment mechanism to reach everyone else is always: portable scripts + binaries, usually wrapped up in some way.
Does CriTcl need a build system? I'm not convinced... - JCW
AK Clarifications.
PT 2003-May-02: For an example of optionally extending tcllib using critcl have a look at the md4 module and the DEVELOPMENT branch of the base64 module (specifically the uuencode and yencode packages). These files include C code to be built with critcl. If tcllib is being packages as a starkit or starpack then using critcl to build the base64c, md4c and md5c packages will enable compiled code for the supported platform. Critcl packages are already installed into a platform dependent subdirectory so for supported packages we get normal tcllib functionality with compiled speed, while for other platforms we still have the pure tcl versions. Personally I think this is the best of all worlds.
Has someone looked at http://root.cern.ch/root/Cint.html
as a possible way to integrate C with Tcl without having to compile C...
AK: Larry Virden provided this pointer:
http://www.purl.org/NET/Tcl-FAQ/part4.html
What: Embedded C (EC) Where: ftp://ftp.reed.edu/pub/users/greaber/ec-0.1.tar.gz Description: Allows you to include C code in your Tcl scripts, compiling and dynamically loading it on the fly. The code will also be cached so the next time you run the program, you don't wait for it to compile. Known to work on DEC OSF/1 V3.2 and SunOS 5.5. Not yet ported to Macintosh or Windows. Updated: 09/1996 Contact: mailto:[email protected] (Grant Reaber)
JH:
In order to have this work with ActiveTcl (Tcl with tcllib), I had to change the first few lines of the critcl.tcl code to:
catch {package require md5} if {[llength [info commands ::md5::md5]]} { interp alias {} ::md5 {} ::md5::md5 }
and it provided some very nice performance numbers on just the md5 stuff:
(jeffh) 60 % time {md5 hello} 1000 801 microseconds per iteration (jeffh) 61 % time {md5c hello} 1000 4 microseconds per iteration
The catch... would break if there was already an "md5" command, wouldn't it? In fact, while I think I understand why that code is written in the way it is, is there a way to do things simpler? - JCW
Maybe the following is a solution:
if {[catch md5]} { catch {package require md5} } if {[catch md5]} { interp alias {} ::md5 {} ::md5::md5 }
It's still extremely messy and weak (brittle) IMO, and illustrates how we seem to be making it harder and harder to write readable, clean, solid code... :-(
A dated article [L2 ] has background information on interpreted C.
More news on newer rev's of CriTcl, or rather the "CritLib" where it is included:
JCW
LV: Has anyone investigated making use of CriTcl to create an HTML rendering widget, perhaps based on BrowseX?
JCW: Yep, Tkhtml can be built with CriTcl, though it's tricky. See [L3 ], now in critlib.
CMcC: I'm a big fan of SWIG, but it's so much easier to deliver extensions (at least small ones) with CriTcl because you can put the whole extension into only one source object, where SWIG source distribution requires at least an interface description, a Makefile (to be useful) and (usually) a .tcl to wrap and sugar it up. You can generate the .so file into ., and package it up as a .tar.gz having run it once. Very convenient.
I don't understand why setting the outdir to local stops automatic recompilation. There doesn't seem to be any really good reason for that, and it gave me a few unexpected results.
I don't see the problem with expecting the user to install Ming under Windows - it's free after all.
Compilation errors could perhaps be thrown, so you don't have to root around in ~/.critcl to find out what happened, and the special case of a lack of C compiler could be handled by a URL for downloading a free C compiler under Windows. I'm presuming most people have gcc under Unix.
Finally, since tclkit can handle .so and .dll loading, and CriTcl can produce them on the developer's machine, and since CriTcl gives you the significant win of being able to package a whole small extension into a single .tcl, I think it's a win for both binary and source distributions.
Thanks for the comments, Colin. The critcl mechanism is still in flux, the most recent work has been to create a self-contained package. It does catch and present errors somewhat better. The "outdir" mechanism is tricky (several features still are quite experimental), but with the packaged version of critcl (by Steve Landers, see [L4 ]) it is no longer needed. See the Critcl page, which has just been updated with more info and examples.
Your comments in the last paragraph are exactly why I think the use of "outdir" is already becoming less important. What I tend to do is develop inline, and simply never bother about how binaries are dealt with, and then when it's ready for deployment, I run "critcl -pkg myscript.tcl" to create shared libs. -jcw
Sep 2002 - Conference paper by Steve Landers and Jean-Claude Wippler is now at [L5 ], with slides from JCW's presentation at [L6 ].
SWT: I have built a working cint shared lib for tcl. It works great! Now to "run" c code the cint library is only needed for each platform that support is required for.
Paolo Noli: A little question: How to call a tcl commands from inside a c funcion declared with the statement "ccode"? (I need this to implement a callback procedure.. but I think this can be an interesting tip for others people. :)