tags:

views:

15

answers:

1

I've an executable hosting tcl interpretor, and a library hosting a extension. I want to be able to build the library dynamically (loaded with Tcl's load) or statically (single executable, or so loaded implicitly).

The Executable code:

#ifdef GO_STATIC
    extern int My_ext_Init(Tcl_Interp* interp);
    Tcl_StaticPackage(interp, "my_ext", My_ext_Init, My_ext_Init);
    My_ext_Init(interp);  // THIS SHOULD NOT BE NEEDED !!
    Tcl_SetVariable(interp, "is_statically_linked", "1", TCL_GLOBAL_ONLY);
#else
    Tcl_SetVariable(interp, "is_statically_linked", "0", TCL_GLOBAL_ONLY);
#endif

The library Code .. can be static or dynamic library ( .a or .so / .lib or .dll ):

int My_ext_Init(Tcl_Interp *interp)
{
 if (Tcl_PkgProvide(interp, "My_ext", "1.0") == TCL_ERROR) {
  return TCL_ERROR;
 }
 Tcl_CreateObjCommand(interp, /*...etc...*/);

}

The startup tcl code:

global is_statically_linked
if {$is_statically_linked} {
    load {} my_ext
} else {
    load my_ext my_ext
}

The problem is .. I really shouldn't be calling My_ext_Init(interp); as it should called by Tcl when I evaluate load {} my_ext

Made community wiki so that the recommended way can be put here.

A: 

Registering a “static package” is done in your application init routine, and should be done after the main interpreter is created (but obviously before you start running your scripts in it). It's a mechanism that's really designed to work the “Big Wish” method of program building, when you use Tcl_Main() to do the work of making an interpreter. When you're doing that, there's a callback into your code (typically called Tcl_AppInit though the name is actually arbitrary) that you can specify and which is the ideal place to put calls to Tcl_StaticPackage. The callback will be called at the right point for you to do the static package registration.

However, that's all considered rather old hat these days. A far better method is to always use dynamic libraries and to instead package everything together as a starkit or starpack. The advantage with doing that is that you just need to build your .so files as stub-enabled (strongly recommended anyway) packages and then you include them in your VFS during the packaging process. After that, you can just do package require and it will all work. (Or you can locate the shared libraries in the virtual mount when running and load them directly.) What's even better is that you can deliver a single .kit file that supports multiple platforms; starpacked executables can't be quite that flexible though, as there are some natural restrictions on portability of binary executables. :-)

Donal Fellows