[Richard Suchenwirth] 2007-10-09 - tcltcc is a Tcl extension wrapping [tcc] (the tiny [C] compiler), which was modified by [MJ] so it: * can do file I/O via [VFS] * is loadable as a Tcl extension * uses Tcl's ck* memory allocation commands LGPL, download at http://code.google.com/p/tcltcc/ . -------------------------------------------------------------------------------------- [jgz] How to install the package ? [RS]: I'd suspect the usual ''.../configure; make; make install'', but for Win32 a complete package is included (see ''package'' directory). [jgz] Installation for Win32 tcl/tk 8.4.16. Running D:\tcl\lib\tcctcl0.2\install\tcc.tcl runs into error because of extra chars after close brace in statement set dir [file join {*}[lrange [file split [info script]] 0 end-1]] what did I wrong? -------------------------------------------------------------------------------------- Like [Odyce], it also comes with a partial [Critcl] API emulation, so hopefully (at least some time in the future) people can just code against a subset of the [Critcl] API and run it with any of the three :^) [MJ] 2007-10-09 - Tclcc now also builds and works (passes the testsuite) on Linux ---- '''Elementary API''' tcc has a single command ''tcc'' to create a compiler instance: tcc tcc_library_path ?output_type? handle A good default ''library_path'' is in the variable ''$::tcc::dir''. ''Output_type'' defaults to ''memory'', if not given, and can be one of: memory exe dll obj preprocess ''handle'' is a string provided by the user to name this instance Once you have an instance (e.g. ''h'') , it accepts the following methods: h add_include_path (path) h add_file (filename) h add_library (filename) h add_library_path (path) h add_symbol h command (tclname) (cname) - create a Tcl command tclname which calls cname h compile (code) - this is the main action, can only be called once per instance h define (symbol) (value) - similar to #define h get_symbol h output_file (filename) - write DLL or EXE file h undefine (symbol) - similar to #undef To delete a tcc instance, just rename h {} In addition, there's a scripted layer on top of these that emulates part of the [Critcl] API, for in-memory compilation: tcc::ccode (code) keeps the code buffered for the following compilations, until ''tcc::reset''. tcc::cproc (name) (argl) (rtype) (body) Creates code to implement a Tcl command ''name'' with typed arguments ''argl'' of C return type ''rtype'' with the specified C ''body'', and compiles and registers it. tcc::reset Clears all code that has been buffered by calls to ''tcc::ccode'' ---- The first (and pretty unique) use case for tcc is that it can compile directly into memory, even in an interactive session. Example: ~ $ tclsh % packa re tcc 0.2 % tcc::cproc sigid {int i} char* {return Tcl_SignalId(i);} % sigid 4 SIGILL is always included, so if you run into an interesting C function, it's evidently extremely easy to wrap it up and try it out. Like in [Odyce] (which also builds on [tcc]), even simple things can substantially reduce runtime if done in C: % tcc::cproc cadd {double a double b} double {return a+b;} % proc tadd {a b} {expr {$a+$b}} % time {cadd 1.2 3.4} 1000 19.777 microseconds per iteration % time {tadd 1.2 3.4} 1000 43.138 microseconds per iteration ---- '''Simple API for building DLLs''' [RS] 2007-10-13: Since a couple of days, tcltcc can also build shared libraries (currently only DLLs for Windows, tested on [Windows 95]). Here's a cute and simple API for that: package require tcc set n [tcc::dll ?name?] Prepares the making of a DLL. Name is generated if not given, and in any case returned. $n ccode string Adds the string (which can be many lines) to the source buffer. Useful for #include/#define etc. preprocessor directives, static internal functions, etc. $n cproc name argl rtype body Creates code to implement a Tcl command ''name'' with typed arguments ''argl'' of C return type ''rtype'' with the specified C ''body'', and appends that to the source buffer. $n write ?-name str -dir path -code string? Produces the DLL $path/$name[[info sharedlibextension]] by compiling the source buffer, creating an Init function which registers the commands as specified by ''cproc'' calls, and optionally adding the initialization code in ''string''. After this call, no other ccode/cproc/write calls are useful. Working example (from the test suite): test tcc-10.3 "new DLL interface" { set d [tcc::dll] $d ccode {static int fib(int n) {return n <= 2? 1 : fib(n-1) + fib(n-2);}} $d cproc fiboy {int n} int {return fib(n);} $d cproc hello {} char* {return "world";} $d write -name fiboy -code {Tcl_Eval(interp,"puts {hello Fiboy!}");} load fiboy[info sharedlibextension] list [fiboy 20] [hello] } {6765 world} For [introspection] and debugging, no cleanup takes place yet. You can see the generated code with set tcc::dll::${d}::code Ah, tcc is great fun... :^) - In the [Tcl chatroom], [Gerald Lester] asked for the converse functionality: wrap Tcl code into a C function that relieves the user of explicit [Tcl_Eval]. See [Tcl to C functions] ---- '''Building executables''' Before there is a simple API like the one for DLLs above, the following session transcript shows how to build and test an .exe main program pedestrianly: % tcc . exe t % t add_file c/crt1.c % t compile {int main(int argc,char*argv[]){printf("hello world %d\n",argc);return(0);}} % t output_file hello.exe % exec hello.exe a b c hello world 4 % Well, that was a dirt simple executable. How about building a complete [tclsh] with an extra [[square]] command? That's takes about 16 lines: test tcc-9.2 {a little tclsh} { set code [tcc::wrapCmd square {double x} double x_square {return x*x;}] append code { int AppInit(Tcl_Interp *interp) { Tcl_CreateObjCommand(interp,"square",x_square,NULL,NULL); return Tcl_Init(interp); } int main(int argc, char *argv[]) { Tcl_Main(argc, argv, AppInit); return 0; } } tcc $::tcc::dir exe t t add_file $::tcc::dir/c/crt1.c t add_library tcl8.5 t compile $code t output_file mytclsh.exe exec mytclsh.exe {<