(The good notes, that may be intermixed within the following are all due to [Kevin Kenny]. I'm only the man, who messed up the clear explanations by Kevin. [de].) To build an 'ordinary' [C]-coded [tcl] [extension] is - more or less - easy. For a start, see [Writing Extensions], and, if you feel an example may helpful, the tcl sampleExtension at http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tcl/sampleextension/ (you have to use cvs, to get it, I don't know a place you can simply download it.) This page tries to give hints about how to build an extension, that may be used by another extension at C level. Or, in other words, extension2 depends on (C-) functions of extension1. Or, again in other words, extension1 exports an API to be used by other extensions. To make this work, there are two tasks. First, build extension1 so, that it exports the API. And second, refer to the exported API while build extension2. The tcl way of doing this, is to use a stubs table. What does this mean? (Note: Taking a look at a working example may often be helpful. Tcl itself exports a stub table. So you have at least one example at hand, to look at. A few extensions also exports a stub table, for example trf (http://www.oche.de/~akupries/soft/trf/). I found snack (http://www.speech.kth.se/snack/) especially helpful, as example, because snack not only exports a stubs table, but also has a simple example, how to use the snack API from a second tcl extension.) [AK]: Another set of useful examples are now [TclXML]/[TclDOM]/[TclXSLT], as they show how an extension uses the Tcl stub, provides its own stub tables, uses a stub not from Tcl, or even does both import and export a stub table (TclDOM/libxml2). [tDOM] does the same. '''How to export a stubs table''' You need four additional files, to export the API of your extension as a stubs table, so that other tcl extensions could use it: * extension.h * extensionDecls.h * extensionStubInit.c * extensionStubLib.c You have to create the file extension.h and put all typedef's and macros, that are needed by the API of your extension, in it. At the end of this file just include extensionDecls.h: #include "extensionDecls.h" In theory, it is possible, to handwrite a extensionDecls.h and a extensionStubInit.c. This is normally not needed. The tcl distribution includes in the directory tools a script named genStubs.tcl. This script generates valid extensionDecls.h and extensionStubInit.c for you, from a definition file. Unfortunately, I haven't found any description of the file format of such a definition file. But the format seems to be fairly simple and half-way self-explanatory (and hopefully doesn't change to often ;-)). The *.decls files in the generic directory of the tcl source distribution are examples. Such a .decls file looks like: library extensionName interface extensionName declare 0 generic { int ExtensionName_Function1( Tcl_Interp* interp ) } declare 1 generic { int ExtensionName_Function2( Tcl_Interp* interp, ClientData foobar ) } ... etc ... That's all. Just wrap normal C prototypes (without the trailing ';') of your API functions, as shown above. Now you could call genStubs.tcl tclsh path/to/genStubs.tcl extensionName.decls GenStubs.tcl only _updates_ extensionDecls.h and extensionStubInit.c; the files already have to exist in the . So, (under unix) 'touch' the files, or fill your legal stuff as header at top, befor the first genStubs.tcl run. ExtensionStubInit.c includes (almost) only a global structur, the stubs table of your extension. A 'normal' tcl extension declares itself in the init function of the extension with something like: Tcl_PkgProvide (interp, "extension", "1.3") A tcl extension, that exports a stubs table must, in addition to this, propagate his stubs table. So, instead the above, just use Tcl_PkgProvideEx (interp, "extension", "1.3", &extensionStubs) In which &extensionStubs is a pointer to the stubs table of your extension in extensionStubInit.c, so to pacify your compiler/linker you also should add a declaration like: extern extensionStubs extensionStubs; to your init.c file. Now add extensionStubInit.c to the files of your extension and recompile. The last step is to create the static library, against which other extensions must be linked, if they want to use your extension. This library is complied from the forth of the above mentioned files: extensionStubLib.c. As far, as I'm aware, you have to write your own version of extensionStubLib.c (or to copy one of the existing example, and trim that to your needs). A simple one could look like: #ifndef USE_TCL_STUBS #define USE_TCL_STUBS #endif #undef USE_TCL_STUB_PROCS #include "tcl.h" #include "extension.h" /* ** Ensure that Tdom_InitStubs is built as an exported symbol. The other stub ** functions should be built as non-exported symbols. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT ExtensionStubs *extensionStubsPtr; /* **---------------------------------------------------------------------- ** ** Extension_InitStubs -- ** ** Checks that the correct version of Extension is loaded and that it ** supports stubs. It then initialises the stub table pointers. ** ** Results: ** The actual version of Extension that satisfies the request, or ** NULL to indicate that an error occurred. ** ** Side effects: ** Sets the stub table pointers. ** **---------------------------------------------------------------------- */ char * Extension_InitStubs (Tcl_Interp *interp, char *version, int exact) { char *actualVersion; actualVersion = Tcl_PkgRequireEx(interp, "extension", version, exact, (ClientData *) &extensionStubsPtr); if (!actualVersion) { return NULL; } if (!extensionStubsPtr) { Tcl_SetResult(interp, "This implementation of Extension does not support stubs", TCL_STATIC); return NULL; } return actualVersion; } Compile this and build a static library out of it. Under unix, this means, do something like this (makefile style): ar cr libextensionstub$(VERSION).a $(STUBOBJ) Well, now you're done, for this side. '''How to use a stubs table''' Well, at least, this is pretty simple. If you want to use the API of extension1 in extension2, you have to include the extension1.h file (the one from above, for now, extension1 is always the 'extension' from above) into the source files of your extension2. Of course. The next thing is to add -DUSE_EXTENSION1_STUBS to the compiler flags of your extension2. And Since you're already in the makefile, just add "-L/path/to/your/extension1/libfile -lextension1stub.a to the libraries, to link extension2 against. The last step is, to announce that you want to use the API of extension1 in your extension2. As a good tcl citizen you already have an #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8", 0) == NULL) { return TCL_ERROR; } #endif in the init file of your extension2, for sure. Just add #ifdef USE_EXTENSION1_STUBS if (Extension1_InitStubs(interp, version, exact) == NULL) { return TCL_ERROR; } #endif recompile, and you're done. ---- Ah, you find this all a bit complicated. Well, I also do. To say the truth, this all wasn't that satisfying. I was able, to make this work on linux, for a given example of extension1 and extension2. But this was not that bit of progress, since under linux, this hole 'using extension1 from extension2' stuff worked (at least under linux and for me) already without this hole stubs hussle, just by exporting the API functions and do the usual. My problem was, that this 'usual' way of doing things - of course, 'usual' depends on the viewpoint - haven't worked at MS plattforms. It still does not. OK, I take this back, and argue the converse. After some struggling (in fact, a lot of, but, to be fair, most may be due to my limited experiences with the MS build tools) I was able to make this work also under windows. Now that I have a basic understanding of what to do, to make an extenstion stubs table and how it works I'm still curious about the 'why'. Sure, with an extenstion stubs table, you get some version independence: you can update extension1, and extension2 still works, without recompilation (the same, as your stubs enabled extension still work after you have updated your tcl installation). My experience is, that at least under linux you don't strictly 'must' use an extension stubs table, even if you have an extension2, that uses functions of an extension1 (just export the API functions of extension1, as you would do for every ordinary library, and you're done). But it seems to me, that under windows you 'must' use a extension stubs table, because it doesn't work also the simple way, as with linux. I'm far away to be an expert in dynamic loading stuff (especially under windows). Someone out there, that could confirm or correct my presumption? And are there other OS'es, for which one must use the extension stubs table mechanism, for this extension2 uses extension1 scenario? ---- On a related subject, [jcw] posted this comment: "Stubs are not limited to tcl.h - this seems to be a common misconception. Did you know that there are over 130 stub definitions for tclInt.h? There's even a (small) third set of stubs for platform-specific calls." ---- [Category Porting]