Critcl FAQ

It is not clear, after reading Critcl pages, 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


Q: When does the code get compiled? In an example such as

  critcl::cproc triple {int i} int {
     return i * 3;    /* this is C code */
  }
  puts "three times 123 is [triple 123]"

when is the C-coded triple command created?

A: When it is called the first time. The critcl::cproc command creates an auto_index entry for the command it defines. The script in this entry causes complete C sources to be written, the compiler to be run, and the resulting dynamic library to be loaded. (It takes longer time than the source or load you'd normally find in such entries, and there are more ways in which it can go wrong, but there is no difference in principle.) Compiled commands are created on a per source-file basis.


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. :)

RS 2007-10-03: Well, the classical way to call Tcl commands from C is Tcl_Eval. The following snippet works as expected (prints "this should come") in Odyce's Critcl emulation, on old faithful W95:

  critcl::cproc do {Tcl_Interp* interp int i char* cmd} ok {
    if(i) Tcl_Eval(interp, cmd);
 }
 do 1 {puts "this should come"}
 do 0 {puts "this should not"}

and runs in local variable scope, as can be verified:

 17% proc f x {do 1 {info locals}}
 18% f 42
 x

In critcl::ccode however you cannot pass in the Tcl_Interp pointer. Maybe arrange for a cproc to deposit the pointer to the (one and only) interp in a global variable?


Instructions for installing critcl in an existing "traditional" (i.e. non-starkit) Tcl installation

  • Critcl is supplied as a Starkit; but perhaps you would like to use it with a traditional Tcl distribution, e.g to use your collection of extensions
  • these instructions are console commands for a Linux/Unix system. Please adapt for other platforms.
  • download the tclkit binary for your platform, and the starkits critcl.kit, and sdx.kit
  • follow the instructions for installing tclkit (you can remove it at the end if you wish)
  • check that tclkit and critcl.kit work correctly: run the command
  tclkit critcl.kit test-critcl.tcl
  • (where tclkit is in your command path and critcl.kit, test-critcl.tcl are in your current directory; the file test-critcl.tcl is listed below)
  • you should see the console output "three times 123 is 369"
  • now use sdx.kit to unpack critcl.kit: run the command
  tclkit sdx.kit unwrap critcl.kit
  • (where tclkit is in your command path and sdx.kit, critcl.kit are in your current directory)
  • a directory critcl.vfs will be created that holds the contents of critcl.kit: cd to this folder's lib subfolder
  cd critcl.vfs/lib
  • ensure that you are the root user and that the folders and their contents have appropriate ownership
  • copy the contents of this folder to the lib folder of your Tcl installation, and then cd there
  cp -a * /path/to/tcl/lib
  cd /path/to/tcl/lib
  • open the file app-critcl/critcl.tcl in a text editor and do the following...
  • ... in the first non-comment line, 'exec tclkit $0 ${1+"$@"}', replace 'tclkit' with 'tclsh'
  • ... find the line with 'Wikit::init' and comment it out (alternatively, install the files from the critcl.vfs/doc folder somewhere on your machine, and specify the path in the 'file join' statement)
  • make the file app-critcl/critcl.tcl executable and symlink it from a directory in your PATH, e.g.
  ln -s /path/to/tcl/lib/app-critcl/critcl.tcl /usr/local/bin/critcl
  • delete your Critcl cache directory ~/.critcl so the next command will test the correct functioning of the compiler
  • now test this installation of Critcl:
  tclsh test-critcl.tcl
  • as before, you should see the console output "three times 123 is 369"
  • once again delete your Critcl cache directory ~/.critcl, and now test the command-line critcl tool (which provides useful command-line options)
  critcl test-critcl.tcl
  • if this is successful, you can now use Critcl from your existing Tcl installation, and you no longer need the tclkit or starkit files to use Critcl

The file test-critcl.tcl:

  lappend auto_path .
  package require critcl

  critcl::cproc triple {int i} int {
     return i * 3;    /* this is C code */
  }
  puts "three times 123 is [triple 123]"

Older versions of the Critcl package builder had a severe bug [L1 ], in that the pkgIndex scripts they generated would conflict with this traditional of use of Critcl. To see if you're affected, enter the commands

 catch {package require f00bar}; # To make sure package indices are loaded.
 package provide critcl ; # This is the result you're interested in

(f00bar should not be the name of an existing package). If the result is empty then all is well, but if it is "0.0" then you've got a bad pkgIndex.tcl script installed.

The sad thing here is that you don't have to use the bad package for anything to be hurt by this; it is sufficient that you have it installed. However, even if you cannot remove the bad package, you can work around it by doing something like the following trickery instead of a normal package require:

  # Save [package ifneeded] scripts for functional versions of critcl.
  set cmds ""
  foreach ver [package versions critcl] {
     if {$ver ne "0.0"} then {
        append cmds [list package ifneeded critcl $ver [package ifneeded critcl $ver]] \n
     }
  }
  # Forget critcl package declarations
  package forget critcl
  # Restore useful critcl package declarations
  eval $cmds
  # Now load a working package
  package require critcl

Sarnold had problems with whitespaces in directory names on Windows XP. Here is the trace :

 gcc -r -nostdlib -DUSE_TCL_STUBS {-IC:/Program Files/msys/1.0/home/St‚phane ARNOLD/.critcl/Windows-x86} -o C:/Program Files/msys/1.0/home/St‚phane ARNOLD/.critcl/Windows-x86/v034_1e3ab721192aa1df5ef708c68f019a0b_pic.o C:/Program Files/msys/1.0/home/St‚phane ARNOLD/.critcl/Windows-x86/v034_1e3ab721192aa1df5ef708c68f019a0b.c  
 gcc.exe: Files/msys/1.0/home/St‚phane: No such file or directory
 gcc.exe: ARNOLD/.critcl/Windows-x86/v034_1e3ab721192aa1df5ef708c68f019a0b_pic.o: No such file or directory
 gcc.exe: C:/Program: No such file or directory
 gcc.exe: Files/msys/1.0/home/St‚phane: No such file or directory
 gcc.exe: ARNOLD/.critcl/Windows-x86/v034_1e3ab721192aa1df5ef708c68f019a0b.c: No such file or directory

I fixed on my local copy of critcl.vfs/lib/critcl/critcl.tcl :

 line 601 : set cmdline "$v::compile $copts -o [list $libfile] [list $base.c] $srcs"
 line 757 : set cmdline "$v::compile $copts [list [file normalize $src]] -o [list $pref.o]"

Please, would you like to fix it ? Thanks in advance.

17jun06 jcw - Fixed in 0.36, thank you.

24oct07 XO - The issue is there again in critcl-new.kit (version2.0). Tweaked the code a little bit, and it worked after I made the following changes...

critcl-new.vfs\lib\critcl\Config

 Line  53:   output   -o [list $outfile]

critcl-new.vfs\lib\critcl\critcl.tcl

 Line 486:   append cmdline " [subst $c::output] [list $src]"
 Line 741:   append cmdline " [list $libfile] "
 Line 900:   append cmdline " [subst $c::output] [list [file normalize $src]]"

AM (26 october 2007) I am pleased to announce that Critcl is now capable of handling Fortran as well - see: Critcl goes Fortran


FM I had to add the option -mno-cygwin to the compilation command line in /critcl/critcl.tcl. That was to force gcc building with mingwin instead of cygwin. (I use both of them under windows). It works. Thank you for this job.


How do I get critcl to run under cygwin? jbr

I created a custom config file by unpacking the starkit and coping critcl3.vfs/lib/critcl/Config.

  sdx unwrap critcl3.exe
  cp critcl3.vfs/lib/critcl/Config critcl.cfg

Then change the defaults compile and link commands to look like this :

compile         /cygwin/bin/gcc-3.exe -mno-cygwin -c
version         /cygwin/bin/gcc-3.exe -mno-cygwin -v
link            /cygwin/bin/gcc-3.exe -mno-cygwin -shared

Invoke thus-ly:

  critcl3 -config critcl.cfg -force -pkg fast.tcl

How do I use Critcl to speed up Tcllib packages under Debian?

I'm using the Tcllib json package to parse thousands of JSON inputs, which is unreasonably slow using the pure Tcl implementation. Fortunately, it was extremely easy to add the compiled C implementation on Debian 12.

These instructions assume you have a local Tcl installation outside of your Debian system's control, in /opt or /usr/local or something similar. If so, you've probably already gone to its lib/ directory and created a symlink to Tcllib, or perhaps copied a Tcllib directory there.

First, install the tcllib-critcl package:

 sudo apt-get update
 sudo apt-get install tcllib-critcl

Second, find out where the package installed the files:

 dpkg -L tcllib-critcl

On Debian 12 amd64, the files are installed in the /usr/lib/tcltk/x86_64-linux-gnu/tcllibc/ directory.

Third, go to your Tcl installation's lib/ directory (where packages live) and create a symlink to the Debian package's directory:

 cd /opt/my-tcl-app/lib       # could also be something like /usr/local/my-tcl-app/lib
 sudo ln -s /usr/lib/tcltk/x86_64-linux-gnu/tcllibc tcllibc

That's all there is to it. Go ahead and benchmark your Tcllib-using script, and see if the performance has improved.

-- GJW 18 Sep 2024