TEA (tclconfig) Source Code

Artifact [62730a3f2d]
Login

Artifact 62730a3f2d4efb39f91d2c357a5dafdf095cb6fa:

Wiki page [practcl make.tcl] by hypnotoad 2016-06-24 15:58:18.
D 2016-06-24T15:58:18.105
L practcl\smake.tcl
N text/x-markdown
U hypnotoad
W 4540
# make.tcl

Practcl projects are geared to perform most of the build process utilizing Tcl as the build system.

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 b12a58cf5962a0ebbff9ae467c37d78c