TEA (tclconfig) Source Code

Artifact [94bcf5d5f1]
Login

Artifact 94bcf5d5f19912194a3cd51dfdd631818e7a5b8d:

Wiki page [Practcl Retrofit] by hypnotoad 2016-06-24 16:21:49.
D 2016-06-24T16:21:49.794
L Practcl\sRetrofit
U hypnotoad
W 4425

For existing projects, which already have an established Makefile system this may not be practical or desired. So for our first example we will provide a minimal shim to allow make to invoke practcl.

The example here is a stylized version of the build system for [odielib](http://fossil.etoyoc.com/fossil/odielib). Bits have been edited for clarity, and may vary slightly from the production code.

<pre><code>
# Minimal make.tcl with a single target
    
set CWD [pwd]
set ::project(builddir) $::CWD
set ::project(srcdir) [file dirname [file normalize [info script]]]
set ::project(sandbox)  [file dirname $::project(srcdir)]
    
if {[file exists [file join $CWD .. tclconfig practcl.tcl]]} {
  source [file join $CWD .. tclconfig practcl.tcl]
} else {
  source [file join $SRCPATH tclconfig practcl.tcl]
}

array set ::project [::practcl::config.tcl $CWD]
::practcl::library create LIBRARY [array get ::project]
LIBRARY source [file join $::project(srcdir) library.ini]
LIBRARY implement $::project(builddir)
set fout [open pkgIndex.tcl w]
puts $fout "
#
# Tcl package index file
#
"
puts $fout [LIBRARY package-ifneeded]
close $fout
</code></pre>

This make script has no options, not targets, and only has a single task which will:
* Read our practcl build rules (in the library.ini file)
* generate a *PKGNAME*.mk file (which is a supplementary list of instructions for the Makefile)
* generate the pkgIndex.tcl file (which will notifies Tcl about the package and how to load it.)

The *library.ini* contains instructions for the *LIBRARY* object. For this package it looks like:

    set SRCPATH [file normalize [my define get srcdir]]

    my add [file join $SRCPATH cmodules btree module.ini]
    my add [file join $SRCPATH cmodules odieutil module.ini]
    my add [file join $SRCPATH cmodules geometry module.ini]

    my define add public-include <tcl.h>
    my define add public-include <assert.h>
    my define add public-include <stdio.h>
    my define add public-include <stdlib.h>
    my define add public-include <string.h>
    my define add public-include <math.h>
    my define add include_dir [my define get builddir]

You will note the "my" in front of many statements. This is because the script is actually invoked within the namespace of a TclOO object. This object is the master controller for the project.

The *add* method introduces a new subordinate object. In this case we have added three modules, which themselves will be objects. The add method has an auto-dectection algorithm to pair the appropriate class for a new subordinate by file extension. If we want more control we could have specified:

    my add class module filename [file join $SRCPATH cmodules btree module.ini]

Modules, in turn, can have subordinates.

The btree module is straightforward:

    set here [file dirname [file normalize [info script]]]
    my add [file join $here tree.tcl]

The [tree.tcl](http://fossil.etoyoc.com/fossil/odielib/info/822483fd556b93ba17510c8bbe1a6c5c40d3946b?txt=1&ln=0) file, in turn defines data structures and functions we want available within our library. That file contains a stream of commands along the lines of:

    my c_structure Tree {
        /* A complete binary tree is defined by an instance of the following
       ** structure
       */
       int (*xCompare)(const void*, const void*); /* Comparison function */
       void *(*xCopy)(const void*);               /* Key copy function, or NULL */
       void (*xFree)(void*);                      /* Key delete function */
       struct TreeElem *top;                      /* The top-most node of the tree */
    };

And 

    my c_function {static void TreeClearNode(TreeElem *p, void (*xFree)(void*))} {
       /* Delete a single node of the binary tree and all of its children */
       if( p==0 ) return;
       if( p->left ) TreeClearNode(p->left, xFree);
       if( p->right ) TreeClearNode(p->right, xFree);
       if( xFree ){
          xFree(p->key);
       }
       Tcl_Free((char *)p);
    }

Methods also exist for injecting arbitrary block of C code into specific places in the resulting C file, defining Tcl commands, and building OO classes.

Source files can also be read in from pure C:

    my add [file join $here md5.c]

or

   my add class csource initfunc Md5_Init filename [file join $here md5.c]


Z 2443155f13d03697aa695b5aea167615