This page is for Hints and Issues involved in getting MkTclApp to work properly. So, far I have been building under windows, and will look to start porting to linux soon. All these comments are about my windows experiences. ---- getting some extensions going on my windows system with visual c++ I needed to add this code: (I don't know what happens on *nix yet) # this is needed to get bwidgets started correctly # for blt, the blt_init does this for us, but bwidgets # has no C code we can call, so we need to do this ourselves # Note, it must agree with what mktclapp thinks we have setup set dir {C:/TCL/lib/bwidget1.4.0} source {C:/TCL/lib/bwidget1.4.0/pkgIndex.tcl} # there is an error in the [info script] call, which returns a bad # value (this is used to compute the auto_path for iwidgets) # so we do it ourselves source {c:/tcl/lib/iwidgets4.0.0/iwidgets.tcl} package require Iwidgets global auto_path lappend auto_path C:/TCL/lib/iwidgets4.0.0/generic \ C:/TCL/lib/iwidgets4.0.0/scripts ---- to package up something for windows, you need to include the .dlls and put them in the same directory with your executable. But, if you do this when seting standalone mode to "no", you might not be able to test your program. So, when testing don't put the .dlls (tcl83.dll, etc.) in the same directory with the executable or that will overide where some code thinks the rest of the tcl library code lives. I.E. Some scripts start a search based on what it thinks is the location of the tcl dll, which is (i think) retrieved from [[info library]. ---- To really test for standalone mode, I rename, or move the tcl directory temporarily. Otherwise you can get fooled and some things will still get read off the disk (like blt files for postscript). But watch out. It is real easy to forget to rename it back when you want to resume working. One gotcha that bit me was that if you leave the directory renamed (ex: c:/tcl/... to c:/tclx/...) and then do a save out of xmktclapp.tcl, (i.e. it was still running before I did the rename - else it won't launch) then it will silently NOT find the library files. You will have a truncated .mta config file and your build might not reflect this (i.e. won't give any errors, but is not built correctly). Then when you run you will get some errors. Always check your .mta file to see that it does have all the files you would expect. I chased this for an hour once. ---- Best to install tcl in c:/tcl/... instead of c:/program files/tcl/... this is because xmktclapp.tcl has a bug in it's other library section. It will not handle directory names with spaces. In the below fragment in proc ReadState, the values of var and value get computed incorrectly, (the 2 commented out statements, replaced with the 2 below it to fix the problem) proc ReadState {fn {quiet 0}} { ... some code ... foreach line [split $text \n] { if {![regexp {^## } $line]} continue if {[lindex $line 0]!="##"} continue #set var [lindex $line 1] #set value [lindex $line 2] set var [lrange $line 1 end-1] set value [lindex $line end] } ... } Another problem is that sometimes this directory gets represented as progrm~1 or some other ugly thing and so might not match up with the long file name when mktclapp is doing a lookup. ---- If you get an error that simply quits with no indications (still on windows systems) sometimes you can figure it out by setting a breakpoint on the line following initerr label. Often Et_Bgerror cannot function properly (esp if you haven't got the init stuff to work yet). The interp->result is a string with the error message. Often I saw messages like: cannot find a suitable init.tcl etc. initerr: Et_EvalF(interp,"Et_Bgerror \"%q\"", interp->result); return TCL_ERROR; ---- I now have blt, bwidgets, iwidgets, itk, and itcl working with mktclapp. I needed to use the version that supports data files (3.8 or greater I believe) path.../bltCanvEps.pro path.../bltGrahp.pro path.../lang/en.rc ex: ## Data:C:/Tcl/lib/blt2.4/bltCanvEps.pro 1 ## Data:C:/Tcl/lib/blt2.4/bltGraph.pro 1 ## Data:C:/Tcl/lib/bwidget1.4.0/lang/en.rc 1 Also libraries: ## OtherLib:C:/Tcl/lib/blt2.4 1 ## OtherLib:C:/Tcl/lib/bwidget1.4.0 1 ## OtherLib:C:/Tcl/lib/itcl3.2 1 ## OtherLib:C:/Tcl/lib/itk3.2 1 ## OtherLib:C:/Tcl/lib/iwidgets4.0.0 1 ## OtherLib:C:/Tcl/lib/iwidgets4.0.0/scripts 1 ---- This was the reference to the version that handles long files (greater than 64k bytes). It may be possible to include a long file (w/o this patch) as a data file, since that generates static integers instead of concatonated strings. Yes, look at www.poSoft.de (Section: Tcl patches/mktclapp). It's a patch of mktclapp 3.9. Not the newest version, but it works perfectly for me. ---- The main reason I get large files is that I also use visual tcl (vtcl) to build my programs. This generates large files if you include lots of widgets (it includes some vtcl library code in line). When I did this, I also had to include a wrapper around this code so I could do my workarounds before invoking the vtcl code. EX: myapp.tcl is generated by vtcl, so: wrapper.tcl: ...do wrapper stuff ... source myapp.tcl This was needed to get things done before all the package requires that could otherwise fail (see my first note above). Then I just told xmktclapp that wrapper.tcl was the startup script. ---- This is what I usually start with now. It works as a windows app (not a console app - so no m.s. dos console window shows up). I have some code there to do a complete tcl trace. Needed this to find some of the errors. #include #include #include #include #include "myapp.h" #include int Et_Init(int argc, char **argv); // -------------------- C main if console task ------------------- int main(int argc, char **argv) { return Et_Init(argc,argv)!=TCL_OK; return 0; } // ------------------ utility - updates screen -------------------- int do_tkupdate(int z) { // optional, handy routine while (Tk_DoOneEvent(TK_ALL_EVENTS | TK_DONT_WAIT)) { z++; } return z; // ignore, I was just curious about this } // ------------------------- // debugging trace routines // ------------------------- void xxxlog(char *what,char *hex,char *name) { static FILE *io; static once = 1; if (once) { io = fopen("xxxlog.txt","w"); once = 0; } else { io = fopen("xxxlog.txt","a"); } if (io) { fprintf(io,"%-15s %8x %s\n",what,hex,name); fclose(io); } } void xxxlog2(char *what,int dec,char *name) { static FILE *io; static once = 1; if (once) { io = fopen("xxxlog.txt","w"); once = 0; } else { io = fopen("xxxlog.txt","a"); } if (io) { fprintf(io,"%-15s %8d %s\n",what,dec,name); fclose(io); } } // -------------------------- // A debugging trace callback // -------------------------- void proc( ClientData clientData, Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *cmdProc, ClientData cmdClientData, int argc, char *argv[]) { char buf[400],*cc; int i,j; static FILE *io; static once = 1; if (once) { io = fopen("xxxlog.txt","w"); once = 0; } strcpy(buf,"???"); for(i = 0 ; i < 199 ; i++ ) { if (command[i] == '\0') { buf[i] = 0; break; } else if (command[i] == '\n') { buf[i] = ' '; } else { buf[i] = command[i]; } } buf[90] = 0; if (io) { fprintf(io,"%3d) %s\n",level,buf); for(j = 0 ; j < argc ; j++ ) { cc = argv[j]; strcpy(buf,"-none-"); for(i = 0 ; i < 65 ; i++ ) { if (cc[i] == '\0') { buf[i] = 0; break; } else if (cc[i] == '\n') { buf[i] = ' '; } else { buf[i] = cc[i]; } } buf[60] = 0; fprintf(io," %2d %s\n",j,buf); } fflush(io); } } // -------------------------- -------------------------- -------------------------- // -------------------------- init blt and maybe a trace ------------------------- // -------------------------- -------------------------- -------------------------- #ifdef WIN32 Blt_Init(); int Itcl_Init(); int Itk_Init(); #endif static Tcl_Interp *theinterp = {0}; int Et_AppInit(Tcl_Interp *interp){ int n; n = Blt_Init(interp); if (Itcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Itk_Init(interp) == TCL_ERROR) { return TCL_ERROR; } // to setup a trace, uncomment out these #if 0 xxxlog("appinit",(char *)interp,"interp"); theinterp = interp; Tcl_CreateTrace(interp, 30, proc, (ClientData) 0); #endif return TCL_OK; } #ifdef WIN32 #include int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { char *cmdline; char *argv[2]; cmdline = GetCommandLine(); argv[0] = cmdline; Et_Init(1,argv); } #endif