Dynamically links a code library (typically written in [C], [C++], or some comparable language) with the program containing the Tcl interpreter. Most extensions use this mechanism. : '''load''' ''fileName'' ?''packageName''? ?''interp''? http://www.purl.org/tcl/home/man/tcl8.5/TclCmd/load.htm If ''fileName'' does not contain any directory separators, the library will be searched for in OS-specific ways. If ''packageName'' is not provided, it is derived from the ''fileName'' by trimming certain prefixes and suffixes and applying capitalization rules (so `/usr/local/lib/libfoobar.so` would become `Foobar`); it is used to locate the name of the initialization function inside the library. If ''interp'' is not supplied, the library is initialized for the current interpreter. <> * What does one need to create an extension to be loaded? * What does one need to load Tk? ---- [Clif Flynt] has made available a useful C extension to load shared libraries that don't know anything about tcl's _Init function. The extension allows one to invoke dlopen to load libraries that do not have Tcl entry points (for use by other things that do have legitimate foo_Init entry points). The dlopen extension is available at: http://noucorp.com/cgi-bin/noucorp/generic.tcl?dir=/var/www/html/tcl/utilities It's a minimal, single C file extension, but it has been known to work on both Windows and Posix (just retested on Linux) ---- **Basics of DLL Creation for Tcl extension** You have a design for some software that will be implemented in a dll written in C (or C++ code with extern "C" {} around it). You must write the active code in a function, and add some initialisation code to register the dll's functions with tcl (Tcl_CreateCommand or Tcl_CreateObjCommand is faster). The initialisation required in the code that compiles to make tclext.dll (the `Tclext_Init` name is composed from the dll name by Tcl): ======c // this is your useful procedure. It can be a C++ or C linked procedure. int tclextfunction (ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { // dosomething - clientdata is a pointer to something the programmer may or may not define return TCL_OK; } #ifdef __cplusplus extern "C" { #endif int PROBE_EXPORT Tclext_Init(Tcl_Interp *interp) { // tcl stubs and tk stubs are needed for dynamic loading, you must have this set as a compiler option #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { Tcl_SetResult(interp, "Tcl_InitStubs failed",TCL_STATIC); return TCL_ERROR; } #endif #ifdef USE_TK_STUBS if (Tk_InitStubs(interp, TCL_VERSION, 1) == NULL) { Tcl_SetResult(interp, "Tk_InitStubs failed",TCL_STATIC); return TCL_ERROR; } #endif Tcl_CreateCommand( "tclextfunction", tclextfunction ); // register your functions with Tcl } #ifdef __cplusplus } #endif ====== Then in Tcl script use ====== load tclext.dll tclextfunction a b c ====== to pass the strings a,b,c to tclextfunction in the array argv - argc will be 3 of course. The ClientData is a pointer to anything (perhaps a global data structure or a class defined by a ClientData statement often dynamically allocated in the `Tclext_Init` function). The reader should be able to find all the required .h files from the net without any more help from me. ---- So what do you do when load, or, even more mysteriously, [package], fails? There are many, many ways for this to happen, and typical built-in diagnostics from supplied loaders are inscrutable. One handy tool for such situations is a dependency utility. Under Windows, DependencyWalker [http://www.dependencywalker.com/] walks dependencies. When you let it load a specific dll, it assists you in determining what other DLLs it needs. ---- [AMG]: I just had a very strange problem with [[load]]. When I screw up and try to call my command without loading the the package first, of course I get an error for the command, but I also get an error when trying to load the package. When I do things in the right order, everything works. Yeah I know, I shouldn't be trying to do things backwards, but I still wonder why the load fails. ======none [andy@toaster|~/e6b]$ tclsh % atc::get_dnlink invalid command name "atc::get_dnlink" % load atc.so couldn't load file "atc.so": atc.so: cannot open shared object file: No such file or directory [andy@toaster|~/e6b]$ tclsh % load atc.so % atc::get_dnlink ABCD conversion failed % info patchlevel 8.6b2 % exec uname -a Linux toaster 3.4.0-andy #2 Fri Jun 1 23:52:05 CDT 2012 i686 Pentium II (Deschutes) GenuineIntel GNU/Linux ====== Just so you know, that "conversion failed" message is the right result. This library is not stubs-enabled. It also does not link against -ltcl8.6. ''Update: linking against -ltcl8.6 doesn't help; this error still happens.'' I'd file a bug report, but the above is all the information I have at the moment. It seems like more is needed, yet I don't currently have any time to research further. ''Update: here's another rather interesting failure mode:'' ======none [andy@toaster|~/e6b]$ tclsh % load per.so % per::get_integer ABCD 0 4 10 % load atc.so couldn't load file "atc.so": atc.so: cannot open shared object file: No such file or directory [andy@toaster|~/e6b]$ tclsh % load atc.so % load per.so couldn't load file "per.so": per.so: cannot open shared object file: No such file or directory ====== Even when the first command doesn't result in an error, if the second or subsequent command is a [[load]], it fails. This makes it impossible to load more than one library. The next step for me is to build the very latest Tcl and see if the problem persists. ''Update 2:'' I just built the most recent trunk (1581f9beac5715890d105a41090756a89b0f3630 2012-06-15 09:39:34 UTC), but the problem persists, exactly the same as before. The system is running Slackware 13.1, if that helps. I might be able to fiddle around in [gdb] if anyone can point me toward something I ought to be looking at. <> ---- **See also** * [ffidl] * [twapi] * [tcom] / [COMet] * [Tcl_InitStubs] * [info loaded] * [info sharedlibextension] <> Tcl syntax help | Arts and crafts of Tcl-Tk programming | Command | Tcl