Stubs are used to avoid having a program that embeds Tcl, or a shared library that extends Tcl be linked to the Tcl shared library.
The stubs mechanism provides a cross-platform dynamic linking mechanism using tables of function pointers. Tcl, Tk, and other extensions and libraries each provide a table of pointers to their interface functions. The client code then obtains a pointer to this table and uses it to look up anc call functions.
When an extension is linked against the Tcl shared library to produce an extension shared library, the runtime linker is then responsible for linking in the Tcl shared library when the exension shared library is loaded. A particular name and version may be recorded in the shared library at when the shared library is created, which can then be problematic when distributing the extension shared library to other parties who bring their own Tcl shared library.
Instead, the extension library defines USE_TCL_STUBS and includes tcl.h, which redefines all Tcl_* function calls as lookups into the Tcl stubs table. The extension library is then linked to the Tcl stubs static library, which gives the extension library a public function called Tcl_InitStubs. The extension also makes a public function, usually called Extensionname_Init available. When Tcl loads the extension shared library, it calls this initialisation function, passing it a handle to the interpreter, This initialisation function then calls Tcl_InitStubs, which gets the stubs table from the interpreter and makes it available to the extension.
This approach achieves the following things:
A shared object that doesn't use stubs to call interface functions of other libraries such as Tcl, but instead is directly linked to those libraries when it is created, it is bound to those libraries by a particular name and version, and it will be necessary to make sure parties to whom the shared object is distributed provide compatible libraries. It will probably also be necessary recompile such a shared object when switching to newer version of the shared libraries it depends on.
A Tcl extension that uses stubs to call into the Tcl or Tk C API can be loaded by any version of Tcl that supports the API required by the extension. Many extensions use stubs in this way, and any extension that is included in starkit must use stubs.
If it provides a C API, an extension (or other library) may also provide a stubs table of its own. This allows other code to dynamically bind to it. For example, TclOO provides a stubs table that other Tcl extensions can use. TclOO, Tk, and memchan are all examples of libraries that both use stubs tables and provide stubs tables.
To see the differences take a look at the following which describes what happens when Tcl loads two different extensions.
Loading an extension which is linked directly to Tcl:
Loading an extension which uses Tcl's stub interface:
Perhaps Jean-Claude Wippler suggested it to Paul Duffin in 1999, and Paul and Jan Nijtmans, with whom Jean-Claude had also been discussing ideas, implemented it in 2000. Others involved in the first generation were ??? (backlinking details) ...
DKF: I certainly remember suggesting something like the mechanism we ended up with back before Paul produced his initial version, though his initial version was a lot more elegant...
Under Linux and similer Unixes, check with ldd. No Tcl or Tk library references should appear. For Windows, do the same with "dumpbin /dependents".
Well, one place is that development against a Tclkit/Starkit/Starpack environment, extensions that are not built using Stubs result in more difficulty. (Or is it actually that they cannot be used at all?)
Is all this stubs stuff necessary? Why does the build system have to be so difficult. Believe us: this is far less difficult than the alternative. Yes, libtool and autoconf are maddening, but there are things outside the Tcl world that demonstrate we don't have it so bad. DKF briefly defends stubs in a follow-up [L1 ] to a lengthy thread that itself touches several aspects of generation.
Helmut Giese notes that, even when compiler providers agree on object formats, they might still construct libraries in incompatible ways. In particular, under Windows, those who choose to work with gcc-based compilation might need to rebuild tclstub84.lib before Stubs-enabled extensions load correctly.
Georgios Petasis and Michael Schlenker observe that Stubs-less languages need "batteries included'', because reliance on version-specific extensions would otherwise be prohibitively onerous: "the C interface of these languages seems so primitive that you have to recompile everything each time a new version is out."
Phils take on stubs Stubs - Another explanation
KBK: "Even in version lockstep, stubs can be handy if only to keep all of your libraries following the same linkage conventions."
hat0 Please note that, in building a cross-platform stub-enabled extension, that Windows may require this modification to your C code's declaration:
- int Extension_Init(Tcl_Interp *interp) + int DLLEXPORT Extension_Init(Tcl_Interp *interp)
Without this, linking may fail in curious ways, with errors such like:
Cannot export ??_C@_03KBFG@Tcl?$AA@: symbol not found Cannot export ??_C@_03PFGM@?$CJ?3?5?$AA@: symbol not found Cannot export ??_C@_0BC@JJNH@?0?5actual?5version?5?$AA@: symbol not found