Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 2 | mjames | 1 | <html><head> |
| 2 | <title>Mktclapp: A tool for building C/C++ programs that use Tcl/Tk</title> |
||
| 3 | </head> |
||
| 4 | <body bgcolor=white> |
||
| 5 | |||
| 6 | <h1>Contents:</h1> |
||
| 7 | <ul> |
||
| 8 | <li><a href="#toc1"> |
||
| 9 | Introduction |
||
| 10 | </a></li> |
||
| 11 | <li><a href="#toc2"> |
||
| 12 | A Quick Overview |
||
| 13 | </a></li> |
||
| 14 | <li><a href="#toc3"> |
||
| 15 | Setting Up Your Development Environment |
||
| 16 | </a></li> |
||
| 17 | <li><a href="#toc4"> |
||
| 18 | Hello, World! |
||
| 19 | </a></li> |
||
| 20 | <li><a href="#toc5"> |
||
| 21 | If You Are Having Trouble |
||
| 22 | </a></li> |
||
| 23 | <li><a href="#toc6"> |
||
| 24 | Adding More Tcl Code |
||
| 25 | </a></li> |
||
| 26 | <li><a href="#toc7"> |
||
| 27 | Making The Program Standalone |
||
| 28 | </a></li> |
||
| 29 | <li><a href="#toc8"> |
||
| 30 | Common Mistakes |
||
| 31 | </a></li> |
||
| 32 | <li><a href="#toc9"> |
||
| 33 | Adding In Some C Code |
||
| 34 | </a></li> |
||
| 35 | <li><a href="#toc10"> |
||
| 36 | Implementing New Tcl Commands In C |
||
| 37 | </a></li> |
||
| 38 | <li><a href="#toc11"> |
||
| 39 | Using The Tcl_Obj Interface For Tcl New Commands |
||
| 40 | </a></li> |
||
| 41 | <li><a href="#toc12"> |
||
| 42 | Using Tcl Namespaces |
||
| 43 | </a></li> |
||
| 44 | <li><a href="#toc13"> |
||
| 45 | Executing Tcl/Tk Commands From C Code |
||
| 46 | </a></li> |
||
| 47 | <li><a href="#toc14"> |
||
| 48 | Other Functions Provided By Mktclapp |
||
| 49 | </a></li> |
||
| 50 | <li><a href="#toc15"> |
||
| 51 | The <tt>%q</tt> Format Field |
||
| 52 | </a></li> |
||
| 53 | <li><a href="#toc16"> |
||
| 54 | Putting A <tt>main()</tt> In Your C Code |
||
| 55 | </a></li> |
||
| 56 | <li><a href="#toc17"> |
||
| 57 | C Functions For Application Initialization |
||
| 58 | </a></li> |
||
| 59 | <li><a href="#toc17a"> |
||
| 60 | Bundling Binary Data Files With The Executable |
||
| 61 | </a></li> |
||
| 62 | <li><a href="#toc17b"> |
||
| 63 | Building Tcl Extensions With Mktclapp |
||
| 64 | </a></li> |
||
| 65 | <li><a href="#toc18"> |
||
| 66 | Running Mktclapp From The Command Line |
||
| 67 | Or In A Makefile |
||
| 68 | </a></li> |
||
| 69 | <li><a href="#toc18b"> |
||
| 70 | Using MkTclApp With The MingW32 Compiler For Windows |
||
| 71 | </a></li> |
||
| 72 | <li><a href="#toc19"> |
||
| 73 | History Of Mktclapp And Summary |
||
| 74 | </a></li> |
||
| 75 | <li><a href="#toc20"> |
||
| 76 | Bibliography |
||
| 77 | </a></li> |
||
| 78 | </ul> |
||
| 79 | <hr> |
||
| 80 | |||
| 81 | <h1 align=center> |
||
| 82 | Mktclapp: A Tool For Building C/C++ Programs |
||
| 83 | That Use Tcl/Tk |
||
| 84 | </h1> |
||
| 85 | <a name="toc1"><!-- AUTO --> |
||
| 86 | <h2 align=center> |
||
| 87 | Introduction |
||
| 88 | </h2> |
||
| 89 | |||
| 90 | <p>Many people think that Tcl/Tk is just a scripting language. |
||
| 91 | They think the only way to use Tcl/Tk is to |
||
| 92 | write a script of Tcl commands, then run that script using |
||
| 93 | either the "tclsh" or "wish" interpreters.</p> |
||
| 94 | |||
| 95 | <p>But this perception is false. |
||
| 96 | At its heart, |
||
| 97 | Tcl/Tk is really a C library, just like Motif, Gtk or MFC. |
||
| 98 | To use Tcl/Tk as it was originally intended, you have to write |
||
| 99 | a C program that calls the library. "Tclsh" and "wish" are |
||
| 100 | just two programs that happen to be implemented using the |
||
| 101 | Tcl/Tk library.</p> |
||
| 102 | |||
| 103 | <p>This is not to disparage the use of scripts that are |
||
| 104 | interpreted by "tclsh" or "wish". |
||
| 105 | The use of scripts is a very powerful idea and has many important |
||
| 106 | applications. |
||
| 107 | But sometimes problems work out better if you approach them with |
||
| 108 | a C or C++ program rather than a script. |
||
| 109 | Unfortunately, the mixing of C or C++ and Tcl/Tk into the same |
||
| 110 | program is a topic that has been neglected in the Tcl/Tk |
||
| 111 | literature and documentation.</p> |
||
| 112 | |||
| 113 | <p>The article is about a utility called <b>mktclapp</b>. |
||
| 114 | Mktclapp simplifies the task of building a program |
||
| 115 | that uses both C/C++ code and Tcl/Tk. |
||
| 116 | Using mktclapp, you can quickly write programs that:</p> |
||
| 117 | <ul> |
||
| 118 | <p><li> Implement powerful GUIs or command-line interfaces using Tcl or |
||
| 119 | Tcl/Tk,</li></p> |
||
| 120 | <p><li> Do speedy computation on complex data structures using C or C++, |
||
| 121 | </li></p> |
||
| 122 | <p><li> Compile under both Unix and Windows98/NT with no source code changes, |
||
| 123 | </li></p> |
||
| 124 | <p><li> Are realized in a single standalone executable file,</li></p> |
||
| 125 | <p><li> Run on machines without "tclsh" or "wish" installed, and</li></p> |
||
| 126 | <p><li> Are difficult for end-users to read and reverse-engineer.</li></p> |
||
| 127 | </ul> |
||
| 128 | |||
| 129 | <p>Mktclapp is very easy to learn to use. |
||
| 130 | If you already know how to program in C and you are familiar |
||
| 131 | with writing Tcl/Tk scripts, then you should be able to start |
||
| 132 | using mktclapp in just a few minutes. |
||
| 133 | If you are inexperienced, it might take you just a little longer, |
||
| 134 | but it still is not hard.</p> |
||
| 135 | |||
| 136 | <a name="toc2"><!-- AUTO --> |
||
| 137 | <h2 align=center> |
||
| 138 | A Quick Overview |
||
| 139 | </h2> |
||
| 140 | |||
| 141 | <p>This is what mktclapp does for you: |
||
| 142 | You begin with a collection of source files, some written in C or C++ |
||
| 143 | and others written in pure Tcl or Tcl/Tk. |
||
| 144 | (See figure 1 below). The mktclapp program scans these source files |
||
| 145 | and uses the information it gleans to build an |
||
| 146 | <b>application initialization</b> module, shown as <b>appinit.c</b> |
||
| 147 | in the figure. |
||
| 148 | You then use your regular C compiler to turn the application initialization |
||
| 149 | module and your C/C++ code into a standalone executable.</p> |
||
| 150 | |||
| 151 | <p> |
||
| 152 | <a name=fig1> |
||
| 153 | <hr><center><img src="fig1.jpg" alt="Figure 1"><br> |
||
| 154 | <b>Figure 1</b></center></p><p><hr></p> |
||
| 155 | |||
| 156 | <p>The mktclapp program performs a number of services for you:</p> |
||
| 157 | |||
| 158 | <ul> |
||
| 159 | <p><li> It takes care of the messy details of creating and |
||
| 160 | initializing a Tcl or Tcl/Tk interpreter.</li></p> |
||
| 161 | <p><li> It converts all your Tcl/Tk scripts into static C strings inside |
||
| 162 | the application initialization module so they |
||
| 163 | will be compiled into the executable.</li></p> |
||
| 164 | <p><li> It optionally "shrouds" your Tcl/Tk scripts so that they are |
||
| 165 | not easily visible to end users.</li></p> |
||
| 166 | <p><li> It provides some extra library functions that make it easier |
||
| 167 | to write C code that invokes Tcl/Tk subroutines.</li></p> |
||
| 168 | <p><li> It registers certain C functions as Tcl/Tk commands so that |
||
| 169 | your Tcl/Tk scripts can directly execute those C functions.</li></p> |
||
| 170 | </ul> |
||
| 171 | |||
| 172 | <p>It short, mktclapp takes care of a lot of the mundate |
||
| 173 | details of writing a mixed C/C++/Tcl/Tk program so that you have more |
||
| 174 | time left over to focus on solving the interesting problems.</p> |
||
| 175 | |||
| 176 | <p>Mktclapp is a command-line program which you can call from your |
||
| 177 | project's Makefile. But there is also a GUI wrapper for mktclapp |
||
| 178 | (written in Tcl/Tk, of course) that makes the program easier |
||
| 179 | to operate. The GUI is called |
||
| 180 | <b>xmktclapp.tcl</b>. With xmktclapp.tcl, all you have to do is |
||
| 181 | select the options you want, choose your C, C++ |
||
| 182 | and Tcl/Tk source files from a file list, and press "Build". |
||
| 183 | The application initialization file will be built for your automatically. |
||
| 184 | Then just run your compiler as you normally would and the job is |
||
| 185 | done. A snapshot of the xmktclapp.tcl GUI is show in figure 2.</p> |
||
| 186 | |||
| 187 | <p> |
||
| 188 | <a name=fig2> |
||
| 189 | <hr><center><img src="xmta1.jpg" alt="Figure 2"><br> |
||
| 190 | <b>Figure 2</b></center></p><p><hr></p> |
||
| 191 | |||
| 192 | <a name="toc3"><!-- AUTO --> |
||
| 193 | <h2 align=center> |
||
| 194 | Setting Up Your Development Environment |
||
| 195 | </h2> |
||
| 196 | |||
| 197 | <p>Are you ready to get started? This section will guide |
||
| 198 | you step-by-step into setting up your development environment to |
||
| 199 | use mktclapp. The process is not difficult and should not take |
||
| 200 | very long. There are three simple steps:</p> |
||
| 201 | |||
| 202 | <ol> |
||
| 203 | <li><p> |
||
| 204 | Make sure you have a suitable ANSI C compiler |
||
| 205 | and POSIX compliant development environment handy. |
||
| 206 | You must have an ANSI-C compiler. Older K&R C compilers will |
||
| 207 | not work.</li></p> |
||
| 208 | |||
| 209 | <p>For the development environment, I like to use some kind |
||
| 210 | of Unix, especially Linux. |
||
| 211 | Unix was originally written by and for software developers, and is |
||
| 212 | an excellent environment for getting a lot of work done in a short |
||
| 213 | amount of time. But mktclapp also works on Windows platforms. |
||
| 214 | For use on Windows, though, you'll need to use the Cygwin |
||
| 215 | (or Mingw32) compiler and development environment. You can download |
||
| 216 | this package for free from |
||
| 217 | <a href="http://sourceware.cygnus.com/cygwin/"> |
||
| 218 | http://sourceware.cygnus.com/cygwin/</a>. |
||
| 219 | Mktclapp will work with VC++, but the use of mktclapp with VC++ is |
||
| 220 | not supported. |
||
| 221 | Please do not send me e-mail asking for help using mktclapp with VC++ or |
||
| 222 | Borland C++. |
||
| 223 | </li> |
||
| 224 | |||
| 225 | <p> |
||
| 226 | <img src=righthand.jpg align=left> |
||
| 227 | <a href="mailto:dlabelle@albany.net">Dennis LaBelle</a> |
||
| 228 | has gotten mktclapp to work with VC++ 6.0. |
||
| 229 | He uses it to build his "Freewrap" program. |
||
| 230 | See <a href="http://www.albany.net/~dlabelle/freewrap/freewrap.html"> |
||
| 231 | http://www.albany.net/~dlabelle/freewrap/freewrap.html</a> for additional |
||
| 232 | Information. |
||
| 233 | </p> |
||
| 234 | |||
| 235 | <li><p> |
||
| 236 | Next, you'll want to download and compile the Tcl/Tk source code. |
||
| 237 | You can find the sources at several sites, including</p> |
||
| 238 | |||
| 239 | <p><ul> |
||
| 240 | <li> <a href="http://www.tclconsortium.org/software/index.vet"> |
||
| 241 | http://www.tclconsortium.org/software/index.vet</a></li> |
||
| 242 | <li> <a href="http://www.scriptics.com/software/download.html"> |
||
| 243 | http://www.scriptics.com/software/download.html</a></li> |
||
| 244 | <li> <a href="http://www.neosoft.com/tcl/"> |
||
| 245 | http://www.neosoft.com/tcl/</a></li> |
||
| 246 | </ul></p> |
||
| 247 | |||
| 248 | <p>The Cygwin environment comes with a copy of Tcl/Tk already built |
||
| 249 | and installed. If you want to compile it yourself (or if you want |
||
| 250 | to use a version of Tcl/Tk other than the version that |
||
| 251 | comes with Cygwin) you may need to |
||
| 252 | download and apply some patches from</p> |
||
| 253 | <ul> |
||
| 254 | <p><li> <a href="http://www.xraylith.wisc.edu/~khan/software/tcl"> |
||
| 255 | http://www.xraylith.wisc.edu/~khan/software/tcl</a></li></p> |
||
| 256 | </ul> |
||
| 257 | |||
| 258 | <p> |
||
| 259 | <img src=righthand.jpg align=left> |
||
| 260 | The Tcl/Tk that comes with the Cygwin compiler requires a special |
||
| 261 | DLL named <b>cygwin1.dll</b>. This DLL is covered by GPL (not |
||
| 262 | the LGPL) and can not be distributed with proprietary software |
||
| 263 | without first paying a $6K licensing fee to Cygnus. If this |
||
| 264 | is a problem for you, you can use the standard Tcl/Tk DLLs from |
||
| 265 | Scriptics that do not require a licensing fee. See |
||
| 266 | <a href="#toc18b">below</a> for details. |
||
| 267 | </p> |
||
| 268 | |||
| 269 | <p>After you download the code, untar it and change to the directory |
||
| 270 | named "tcl*/unix". In that directory, type "./configure" and |
||
| 271 | then type "make". This will build Tcl for you. After building |
||
| 272 | Tcl, cd to "../../tk*/unix" and there type "./configure" and "make". |
||
| 273 | This will build Tk.</p> |
||
| 274 | |||
| 275 | <p> |
||
| 276 | <a name=RecordLibraries> |
||
| 277 | <img src=righthand.jpg align=left> |
||
| 278 | <b>IMPORTANT:</b> While building both Tcl and Tk, notice the sequence of |
||
| 279 | library directives that the Makefile gives to the C compiler when it |
||
| 280 | is linking "tclsh" and "wish". These directives will look something |
||
| 281 | like the following:</p> |
||
| 282 | <blockquote> |
||
| 283 | <b><tt>-ltk8.0 -ltcl8.0 -L/usr/X11R6/lib -lX11 -lm -ldl</tt></b> |
||
| 284 | </blockquote> |
||
| 285 | <p>The exact sequence of libraries varies from one system to another. |
||
| 286 | Write down the libraries that your systems uses. You will need to |
||
| 287 | type in the exact same sequence of libraries when you compile your |
||
| 288 | own applications later on.</p> |
||
| 289 | |||
| 290 | <p>If you are using Cygwin beta19, the compiler options you need |
||
| 291 | to remember look like the line shown below. Note that several extra |
||
| 292 | libraries have been added to this list since version 2.1 of Mktclapp!</p> |
||
| 293 | <blockquote> |
||
| 294 | <b><tt>-Wl,--subsystem,windows -ltk80 -ltcl80 -lm -lkernel32 -lgdi32 -luser32 -comdlg32</tt></b> |
||
| 295 | </blockquote> |
||
| 296 | <p>With Cygwin beta20 or later, the libraries you will need are like this:</p> |
||
| 297 | <blockquote> |
||
| 298 | <b><tt>-mwindows -ltk80 -ltcl80 -lm</tt></b> |
||
| 299 | </blockquote> |
||
| 300 | </li></p> |
||
| 301 | |||
| 302 | |||
| 303 | <p><li> |
||
| 304 | Download and compile mktclapp. You can get the sources to mktclapp |
||
| 305 | from |
||
| 306 | <ul> |
||
| 307 | <p><li> <a href="http://www.hwaci.com/sw/mktclapp/"> |
||
| 308 | http://www.hwaci.com/sw/mktclapp/</a>.</li></p> |
||
| 309 | </ul> |
||
| 310 | <p>The source code to mktclapp is a single file of C code named |
||
| 311 | <b>mktclapp.c</b>. There is no makefile. There really isn't a |
||
| 312 | need for one. To build mktclapp you type this command:</p> |
||
| 313 | <blockquote> |
||
| 314 | <b>cc -o mktclapp mktclapp.c</b> |
||
| 315 | </blockquote> |
||
| 316 | <p>The source code to mktclapp is very portable and should compile |
||
| 317 | without modification and without the need for special compiler |
||
| 318 | switches on any ANSI C compiler.</p> |
||
| 319 | |||
| 320 | <p>The source code to xmktclapp.tcl is also a single file. But xmktclapp.tcl |
||
| 321 | is a Tcl/Tk script, so it requires no compilation. All you have |
||
| 322 | to do is download it.</li></p> |
||
| 323 | </ol> |
||
| 324 | |||
| 325 | <p>Now your environment should be setup and ready to build some |
||
| 326 | great programs using mktclapp. Let's get starting.</p> |
||
| 327 | |||
| 328 | <a name="toc4"><!-- AUTO --> |
||
| 329 | <h2 align=center> |
||
| 330 | Hello, World! |
||
| 331 | </h2> |
||
| 332 | |||
| 333 | <p>We'll begin by using xmktclapp.tcl to build a simple program that |
||
| 334 | involves just 9 lines of Tcl/Tk and no C/C++. |
||
| 335 | The Tcl/Tk code is contained in a single file named <b>hello.tcl</b> |
||
| 336 | and looks like this:</p> |
||
| 337 | |||
| 338 | <blockquote><pre> |
||
| 339 | <b>button .b -text Go -command Hello |
||
| 340 | button .e -text Quit -command exit |
||
| 341 | pack .b .e -side left |
||
| 342 | proc Hello {} { |
||
| 343 | catch {destroy .hi} |
||
| 344 | toplevel .hi |
||
| 345 | button .hi.b -text {Hello, World!} -command {destroy .hi} |
||
| 346 | pack .hi.b |
||
| 347 | }</b> |
||
| 348 | </pre></blockquote> |
||
| 349 | |||
| 350 | <p>This code creates a small window containing two buttons labeled |
||
| 351 | "Go" and "Quit". If you press the Quit button, the program exits. |
||
| 352 | If you press "Go", it pops up another small window containing a |
||
| 353 | single button labeled "Hello, World!". If you press the Hello, World! |
||
| 354 | button, the new window disappears.</p> |
||
| 355 | |||
| 356 | <p>To build your first mktclapp program, first type the code above |
||
| 357 | into a file named <b>hello.tcl</b>. Then, just to make sure you |
||
| 358 | didn't mistype anything, run the script by double-clicking the |
||
| 359 | icon in Windows or in Unix by typing:</p> |
||
| 360 | |||
| 361 | <blockquote><b>wish hello.tcl</b></blockquote> |
||
| 362 | |||
| 363 | <p>Once you are satisfied that the script is right, launch xmktclapp.tcl |
||
| 364 | by typing</p> |
||
| 365 | |||
| 366 | <blockquote><b>wish xmktclapp.tcl</b></blockquote> |
||
| 367 | |||
| 368 | <p>If you are using windows and have installed a binary release |
||
| 369 | of Tcl/Tk from Scriptics, then you can double-click on the |
||
| 370 | xmktclapp.tcl icon to launch it. But when you do, you will |
||
| 371 | not be running the Cygwin version of Tcl/Tk. This can cause |
||
| 372 | some problems. It is best to run xmktclapp.tcl using the |
||
| 373 | Cygwin version of the Tcl/Tk interpreter. To do so, bring |
||
| 374 | up a Cygwin DOS box and type</p> |
||
| 375 | |||
| 376 | <blockquote><b>cygwish80 xmktclapp.tcl</b></blockquote> |
||
| 377 | |||
| 378 | <p>After you get xmktclapp.tcl running, you should see a screen like |
||
| 379 | <a href="#fig2">figure 2</a>. |
||
| 380 | Now change the <b>Settings</b> page of xmktclapp.tcl to look exactly like |
||
| 381 | figure 2. Specifically, set the Application Mode to Tcl/Tk, |
||
| 382 | set Fork Into Background, Standalone |
||
| 383 | and Shroud all to No, set Command Line Input to None, |
||
| 384 | set the name of the Configuration File to <b>hello.mta</b> and |
||
| 385 | the name of the Output File to <b>hello.c</b>.</p> |
||
| 386 | |||
| 387 | <p>Don't worry about the contents of the <b>Libraries</b> page on |
||
| 388 | the xmktclapp.tcl screen at this point. The libraries only |
||
| 389 | come into play if you set Standalone to "Yes" or "Strict". |
||
| 390 | But do go over to the |
||
| 391 | <b>C/C++ Modules</b> pages and make sure |
||
| 392 | it is blank. Use the "Delete" button if necessary to |
||
| 393 | clear it out.</p> |
||
| 394 | |||
| 395 | <p>On the "Tcl Scripts" page, you have to insert the name of your |
||
| 396 | Tcl script in two places, as shown in figure 3.</p> |
||
| 397 | |||
| 398 | <p><center> |
||
| 399 | <img src="xmta-fig3.jpg" alt="figure 3"><br> |
||
| 400 | Figure 3 |
||
| 401 | </center></p> |
||
| 402 | |||
| 403 | <p>Be sure the hello.tcl script appears in both the list box on top and |
||
| 404 | in the "Startup Script" entry box down below. |
||
| 405 | When everything looks right, select the File/Build menu option, |
||
| 406 | or go back to the "Settings" page and press the "Build" button. |
||
| 407 | The build will create files named <b>hello.c</b> and <b>hello.h</b>.</p> |
||
| 408 | |||
| 409 | <p>Referring back to <a href="#fig1">figure 1</a>, what you have just |
||
| 410 | done is the first step of the compilation process. You have run |
||
| 411 | mktclapp on your C, C++ and Tcl/Tk source files in order to generate |
||
| 412 | an application initialization file. In this particular instance you |
||
| 413 | don't happen to be using any C or C++ source files, only Tcl/Tk |
||
| 414 | files. But the idea is still the same. The |
||
| 415 | next step is to run the C compiler.</p> |
||
| 416 | |||
| 417 | <p>The command to compile your program will be something like this:</p> |
||
| 418 | |||
| 419 | <blockquote> |
||
| 420 | <b>gcc hello.c -ltk8.0 -ltcl8.0 -L/usr/X11R6/lib -lX11 -lm -ldl</b> |
||
| 421 | </blockquote> |
||
| 422 | |||
| 423 | <p>The above works on RedHat Linux. If you are using Cygwin version 20 on |
||
| 424 | a Windows machine, the following command is what you need:</p> |
||
| 425 | |||
| 426 | <blockquote> |
||
| 427 | <b>gcc hello.c -ltk80 -ltcl80 -lm -mwindows</b> |
||
| 428 | </blockquote> |
||
| 429 | |||
| 430 | <p>Other platforms will have slightly different variations. |
||
| 431 | But the basic recipe is simple: Start with the name of your C compiler |
||
| 432 | (<b>gcc</b> in the example) and add to this the name of all your C |
||
| 433 | or C++ source |
||
| 434 | files. (We have none for this example.) |
||
| 435 | Then add on the name of the application initialization file: |
||
| 436 | <b>hello.c</b>. |
||
| 437 | Next, add on all those library directives that you wrote down |
||
| 438 | <a href="#RecordLibraries">above</a> when you were compiling Tcl/Tk. |
||
| 439 | Finally, press return and wait for the compiler to do its thing.</p> |
||
| 440 | |||
| 441 | <p>The result is your executable in a file named <b>a.out</b> |
||
| 442 | (or <b>a.exe</b> if you are using Cygwin on Windows.) Type</p> |
||
| 443 | |||
| 444 | <blockquote><b>./a.out</b></blockquote> |
||
| 445 | |||
| 446 | <p>to give it a try (or double click the <b>a.exe</b> icon if you |
||
| 447 | are using Windows.)</p> |
||
| 448 | |||
| 449 | <a name="toc5"><!-- AUTO --> |
||
| 450 | <h2 align=center> |
||
| 451 | If You Are Having Trouble |
||
| 452 | </h2> |
||
| 453 | |||
| 454 | <p>Are you having difficulty getting your first mktclapp program to compile |
||
| 455 | or run? |
||
| 456 | This section is designed to help you fix the problem.</p> |
||
| 457 | |||
| 458 | <p><img src=righthand.jpg align=left> |
||
| 459 | <b>Problem:</b> |
||
| 460 | The compiler complains that it can't find library <i>ABC</i>.<br clear=both></p> |
||
| 461 | |||
| 462 | <p>First, make sure you entered the library options to the compiler exactly |
||
| 463 | as they were used when compiling Tcl/Tk. See the |
||
| 464 | discussion <a href="#RecordLibraries">above</a> for details.</p> |
||
| 465 | |||
| 466 | <p>If it still doesn't work, it may be because your a compiling in a different |
||
| 467 | directory from the one in which Tcl/Tk was built. Try adding a |
||
| 468 | couple of <b>-L</b> |
||
| 469 | options to the beginning of the library switches that defines the directories |
||
| 470 | that contain your Tcl and Tk libraries. Perhaps something like this:</p> |
||
| 471 | |||
| 472 | <blockquote> |
||
| 473 | <b>gcc appinit.c -L../tk8.0.3/unix -ltk8.0 -L../tcl8.0.3/unix/ \<br> |
||
| 474 | -ltcl8.0 -L/usr/X11R6/lib -lX11 -lm -ldl</b> |
||
| 475 | </blockquote> |
||
| 476 | |||
| 477 | <p>The <b>-L</b> option tells the compiler what directories to look in for |
||
| 478 | the libraries you specify. The compiler is often able to figure out |
||
| 479 | these directories on its own, but sometimes you have to give it hints.</p> |
||
| 480 | |||
| 481 | <p>If that still isn't working, try typing the filename of the libraries |
||
| 482 | themselves instead of using the <b>-l</b> options. Like this:</p> |
||
| 483 | |||
| 484 | <blockquote> |
||
| 485 | <b>gcc appinit.c ../tk8.0.3/unix/libtk8.0.a ../tcl8.0.3/unix/libtcl8.0.a \<br> |
||
| 486 | -L/usr/X11R6/lib -lX11 -lm -ldl</b> |
||
| 487 | </blockquote> |
||
| 488 | |||
| 489 | <p> |
||
| 490 | <img src=righthand.jpg align=left> |
||
| 491 | <b>Problem:</b> |
||
| 492 | The program compiles, but when I try to run it a message |
||
| 493 | says that Tcl/Tk was installed incorrectly.<br clear=both></p> |
||
| 494 | |||
| 495 | <p>This problem can arise if you have two or more incompatible versions of |
||
| 496 | Tcl/Tk installed on your development machine. The error message occurs |
||
| 497 | when you try to use the C library from one version of Tcl/Tk and the Tcl/Tk |
||
| 498 | Script Library from an incompatible version.</p> |
||
| 499 | |||
| 500 | <p>A quick fix is to set your TCL_LIBRARY and TK_LIBRARY environment variables |
||
| 501 | to point to the appropriate versions of the Tcl/Tk Library scripts for the |
||
| 502 | version of the C library you are using. If you are using the C library |
||
| 503 | at <b>../tk8.0.3/unix/libtk8.0.a</b>, then an appropriate setting for |
||
| 504 | the TK_LIBRARY environment variable would be <b>../tk8.0.3/library</b>. |
||
| 505 | The TCL_LIBRARY variable is set analogously.</p> |
||
| 506 | |||
| 507 | <p>A more permanent fix (and one that you should use for all your |
||
| 508 | deliverables) is to make your program standalone. To do this, change |
||
| 509 | the "Standalone?" option on the Settings page of xmktclapp.tcl to either |
||
| 510 | "Yes" or "Strict". |
||
| 511 | Then go to the "Libraries" page and enter an appropriate path for both |
||
| 512 | your Tcl and your Tk script libraries. These paths will be exactly the |
||
| 513 | same paths you used for the TCL_LIBRARY and TK_LIBRARY environment varibles |
||
| 514 | in the quick fix described by the previous paragraph. Then press |
||
| 515 | the "Build" button, exit xmktclapp.tcl, and recompile.</p> |
||
| 516 | |||
| 517 | <p>This problem occurs most often on Windows because people tend to |
||
| 518 | have two versions of Tcl/Tk installed there. There is probably a |
||
| 519 | binary release of Tcl/Tk installed and the version of Tcl/Tk that |
||
| 520 | came with the Cygwin compile. If this is your situation, you need |
||
| 521 | to make absolutely sure that the Tcl/Tk Libraries you are using come |
||
| 522 | from the Cygwin compiler release and not the other Tcl/Tk installation.</p> |
||
| 523 | |||
| 524 | <p><img src=righthand.jpg align=left> |
||
| 525 | <b>Problem:</b> On windows, I double click on the program icon, but |
||
| 526 | nothing happens.<br clear=both></p> |
||
| 527 | |||
| 528 | <p>This could be one of several things. Mostly likely it is because Windows |
||
| 529 | cannot find the right DLLs to run your program. You need to make a |
||
| 530 | copy of the following three files from the "bin" directory of your |
||
| 531 | Cygwin installation into the same directory where your new executable |
||
| 532 | is found: |
||
| 533 | <ul> |
||
| 534 | <li> <b>cygwin1.dll</b> (or <b>cygwin19.dll</b> under Cygwin version 19) |
||
| 535 | <li> <b>cygtcl80.dll</b> |
||
| 536 | <li> <b>cygtk80.dll</b> |
||
| 537 | </ul> |
||
| 538 | If putting these three files in the same directory as the executable |
||
| 539 | doesn't help, then try running the program manually from the Cygwin |
||
| 540 | shell prompt. You might get a better error message then. If you |
||
| 541 | still cannot figure out what is going wrong, try using the remedy to |
||
| 542 | the previous problem -- make the program standalone and/or set your |
||
| 543 | TCL_LIBRARY and TK_LIBRARY environment variables. If all else fails, |
||
| 544 | run your program in the debugger to see where it is going astray.</p> |
||
| 545 | |||
| 546 | <p><img src=righthand.jpg align=left> |
||
| 547 | <b>Problem:</b> When I compile using the Cygwin compiler I get an error |
||
| 548 | message that says "cannot find entry symbol _winMainCRTStartup". |
||
| 549 | <br clear=both></p> |
||
| 550 | |||
| 551 | <p>The Cygwin compiler always gives this error message when you compile |
||
| 552 | using the "-mwindows" option. But it isn't really an error. If you |
||
| 553 | didn't see any other error messages then you executable should still |
||
| 554 | work.</p> |
||
| 555 | |||
| 556 | <a name="toc6"><!-- AUTO --> |
||
| 557 | <h2 align=center> |
||
| 558 | Adding More Tcl Code |
||
| 559 | </h2> |
||
| 560 | |||
| 561 | <p>Now let's consider the case where your program consists of two |
||
| 562 | or more Tcl files. Typically the way this works is that the |
||
| 563 | first Tcl file (the "main" Tcl file) uses the "source" command of |
||
| 564 | Tcl to load the contents of all the other Tcl files.</p> |
||
| 565 | |||
| 566 | <p>Suppose, for example, we what to add ballon help to the "Hello World" |
||
| 567 | program we constructed above. I like to use |
||
| 568 | <a href="mailto:d.roche@lectra.com">Daniel Roche's</a> excellent |
||
| 569 | <b>balloon.tcl</b> code. You can get a copy directly from |
||
| 570 | Daniel's website at</p> |
||
| 571 | |||
| 572 | <blockquote> |
||
| 573 | <a href="http://www.multimania.com/droche/tkballoon/index.html"> |
||
| 574 | http://www.multimania.com/droche/tkballoon/index.html</a> |
||
| 575 | </blockquote> |
||
| 576 | |||
| 577 | <p>Or you can grab a <a href="balloon.tcl">mirrored copy</a> directly |
||
| 578 | from the mktclapp website. |
||
| 579 | However you get it, add in |
||
| 580 | the <b>balloon.tcl</b> package by altering <b>hello.tcl</b> |
||
| 581 | to look something like this:</p> |
||
| 582 | |||
| 583 | <blockquote><pre> |
||
| 584 | <b>source balloon.tcl |
||
| 585 | button .b -text Go -command Hello |
||
| 586 | set_balloon .b {Press for a new window} |
||
| 587 | button .e -text Quit -command exit |
||
| 588 | set_balloon .e {Exit this program} |
||
| 589 | pack .b .e -side left |
||
| 590 | proc Hello {} { |
||
| 591 | catch {destroy .hi} |
||
| 592 | toplevel .hi |
||
| 593 | button .hi.b -text {Hello, World!} -command {destroy .hi} |
||
| 594 | set_balloon .hi.b {Make this window disappear} |
||
| 595 | pack .hi.b |
||
| 596 | }</b> |
||
| 597 | </pre></blockquote> |
||
| 598 | |||
| 599 | <p>The key thing you need to notice |
||
| 600 | is the first line. We are using the "source" |
||
| 601 | command of Tcl to load in the balloon package. (We also added |
||
| 602 | various calls to "set_balloon". |
||
| 603 | But that isn't the point of this exercise. You should |
||
| 604 | focus on the "source" command on the first line of the script.)</p> |
||
| 605 | |||
| 606 | <p>In a normal Tcl script, the "source" command looks to the disk, |
||
| 607 | finds the file named in its argument, and read the text of that |
||
| 608 | file in as a Tcl script. But with |
||
| 609 | mktclapp, the "source" command works a little differently. |
||
| 610 | With mktclapp, the "source" command first checks to see if the |
||
| 611 | file named in the argument has been compiled into the executable. |
||
| 612 | If the named file is part of the executable, then it is executed |
||
| 613 | directly out of memory, not off of the disk. This feature is |
||
| 614 | the magic of mktclapp. It eliminates the need to have various |
||
| 615 | Tcl scripts on the local disk drive and thus allows you to build a |
||
| 616 | standalone application.</p> |
||
| 617 | |||
| 618 | <p>To compile our revised program, bring up xmktclapp.tcl again |
||
| 619 | and add the <b>balloon.tcl</b> file to the "Tcl Scripts" page. |
||
| 620 | When you are done, it should look something like this:</p> |
||
| 621 | |||
| 622 | <p><center> |
||
| 623 | <img src="xmta-fig5.jpg" alt="unnumbered figure"> |
||
| 624 | </center><p> |
||
| 625 | |||
| 626 | <p>Notice that both Tcl source files, <b>hello.c</b> and |
||
| 627 | <b>balloon.tcl</b>, are listed in the top listbox. This means |
||
| 628 | both files will be compiled into the executable as strings. |
||
| 629 | But <b>hello.tcl</b> is still the main script, the script that |
||
| 630 | runs first and gets everything else running, so it alone is |
||
| 631 | shown below in the "Startup Script" entry.</p> |
||
| 632 | |||
| 633 | <p>After you get xmktclapp.tcl to look like the figure above, use |
||
| 634 | the File/Build menu option to construct the <b>hello.c</b> and |
||
| 635 | <b>hello.h</b> output files. Then recompile the example |
||
| 636 | program just like we did above.</p> |
||
| 637 | |||
| 638 | <blockquote> |
||
| 639 | <b>gcc hello.c -ltk80 -ltcl80 -lm -mwindows</b> |
||
| 640 | </blockquote> |
||
| 641 | |||
| 642 | <p>The result is a executable named <b>a.exe</b> (or |
||
| 643 | <b>a.out</b> on Unix) that contains both the <b>hello.tcl</b> |
||
| 644 | and <b>balloon.tcl</b> scripts built in. You can run this |
||
| 645 | program and it will "source" the balloon.tcl script even if |
||
| 646 | the balloon.tcl script doesn't really exist on the target |
||
| 647 | machine.</p> |
||
| 648 | |||
| 649 | <a name="toc7"><!-- AUTO --> |
||
| 650 | <h2 align=center> |
||
| 651 | Making The Program Standalone |
||
| 652 | </h2> |
||
| 653 | |||
| 654 | <p>The programs we built above do not depend on the files <b>hello.tcl</b> |
||
| 655 | and <b>balloon.tcl</b>. The contents of those files have been compiled |
||
| 656 | into the executable, so the program will run on machines that do have |
||
| 657 | those files resident. But the program still will not run on machines |
||
| 658 | that do not have Tcl/Tk installed. This is because every Tcl/Tk |
||
| 659 | program depends on a couple dozen Tcl script files that are part |
||
| 660 | of the Tcl/Tk installation. These files are sometimes call "Tcl/Tk |
||
| 661 | Initialization Scripts" or the "Tcl/Tk Library".</p> |
||
| 662 | |||
| 663 | <p>You can see a list of the Tcl/Tk Library scripts on your machine |
||
| 664 | be starting up a copy of "wish" and entering the following command:</p> |
||
| 665 | |||
| 666 | <blockquote><pre> |
||
| 667 | <b>lsort [concat [glob $tcl_library/*] [glob $tk_library/*]] |
||
| 668 | </b></pre></blockquote> |
||
| 669 | |||
| 670 | <p>If you have more than one version of Tcl/Tk installed on your |
||
| 671 | machine, then you will have more than one Tcl/Tk Library. On |
||
| 672 | my main development machine, I have both Tk7.6 and Tk8.0 installed. |
||
| 673 | So I will get a different response to the above command depending |
||
| 674 | on whether I run "wish" or "wish8.0".</p> |
||
| 675 | |||
| 676 | <p>Here's the issue: In order to make your programs completely standalone, |
||
| 677 | so that they will run on machines that do not have Tcl/Tk installed, you |
||
| 678 | have to make sure all of the Tcl/Tk Library scripts are compiled in.</p> |
||
| 679 | |||
| 680 | <p>To accomplish this goal, |
||
| 681 | all you have to do is enter the name of |
||
| 682 | the directories that contain your Tcl and Tk libraries on the |
||
| 683 | "Libraries" page of xmktclapp.tcl, then on the "Settings" page set |
||
| 684 | Standalone to either "Yes" or "Strict". |
||
| 685 | When you do this, all the Tcl/Tk Library scripts will be added to your |
||
| 686 | program automatically.</p> |
||
| 687 | |||
| 688 | <p>You may want to avoid making your program standalone during early |
||
| 689 | development. There are a lot of Tcl/Tk Library scripts. Their |
||
| 690 | total size approaches a half megabyte. Your code will compile a lot |
||
| 691 | faster if you leave them out at the beginning. Just be sure to |
||
| 692 | include the library scripts before you ship your program so that |
||
| 693 | people that do not have Tcl/Tk installed will be able to run your |
||
| 694 | code.</p> |
||
| 695 | |||
| 696 | <p>There's more: To be truely standalone, your program should also |
||
| 697 | be statically linked. This means you will need to link against |
||
| 698 | static libraries for Tcl and Tk instead of the usual shared libraries. |
||
| 699 | Otherwise, your program will not run on machines that do not have |
||
| 700 | the Tcl/Tk shared libraries installed.</p> |
||
| 701 | |||
| 702 | <p>On Unix systems, the usual way to link against static libraries |
||
| 703 | is to add an option like <b>-static</b> or perhaps <b>-Bstatic</b> |
||
| 704 | to the last compiler command line. This will do the trick if |
||
| 705 | static libraries are available on your system. If static libraries |
||
| 706 | are not available, you may need to recompile Tcl/Tk to generate |
||
| 707 | them. You might also need to specify the name of the static |
||
| 708 | library directly, as in <b>../tcl8.0/unix/libtcl.a</b> instead |
||
| 709 | of using the "-l" option like this: <b>-ltcl8.0</b>. |
||
| 710 | Most Unix systems have an "ldd" command which will tell you what |
||
| 711 | shared libraries a program needs. Do whatever it takes to get |
||
| 712 | this list down to only those libraries you know will be on |
||
| 713 | every system.</p> |
||
| 714 | |||
| 715 | <p>You may notice that statically linking your program |
||
| 716 | causes it to be much larger. A typical |
||
| 717 | "Hello, World" Tk program will grow to be a couple of megabytes |
||
| 718 | or more in size. It takes a lot longer to compile, and uses |
||
| 719 | more disk space. So, again, you might want to hold |
||
| 720 | off on making your program fully standalone until just before |
||
| 721 | final testing and delivery.</p> |
||
| 722 | |||
| 723 | <p>Statically linking a program on Windows is more problematic. |
||
| 724 | I usually deal with the problem by ignoring it altogether. |
||
| 725 | For Windows builds, I just ship the resulting EXE file together |
||
| 726 | with the DLLs it needs in the same directory on a CD-ROM. |
||
| 727 | This works on Windows because Windows programs look for the |
||
| 728 | DLLs they need in the same directory as the EXE file. |
||
| 729 | (Unix systems do not work this way for security reasons. Windows |
||
| 730 | can get away with it because it has no security, other than |
||
| 731 | the fact that it is a single-user operating system.) |
||
| 732 | After you compile your EXE on Windows, you can find out what |
||
| 733 | DLLs it needs using this command:</p> |
||
| 734 | |||
| 735 | <blockquote><pre> |
||
| 736 | <b>objdump -p a.exe | grep DLL |
||
| 737 | </b></pre></blockquote> |
||
| 738 | |||
| 739 | <p>The <b>kernel32.dll</b> file is part of Windows and doesn't need |
||
| 740 | to be included with your program. I typically ship with just |
||
| 741 | these extra DLLs: <b>cygwin1.dll</b>, <b>cygtcl80.dll</b> and |
||
| 742 | <b>cygtk80.dll</b>.</p> |
||
| 743 | |||
| 744 | <a name="toc8"><!-- AUTO --> |
||
| 745 | <h2 align=center> |
||
| 746 | Common Mistakes |
||
| 747 | </h2> |
||
| 748 | |||
| 749 | <p>Here are some mistakes people commonly make when |
||
| 750 | they are first beginning to use mktclapp. |
||
| 751 | Take care to avoid these mistakes yourself.</p> |
||
| 752 | |||
| 753 | <ul> |
||
| 754 | <p><li> |
||
| 755 | The name of the argument to the "source" command must |
||
| 756 | match exactly, character-for-character, the name that |
||
| 757 | appears in the upper "Tcl Scripts" listbox of xmktclapp.tcl. |
||
| 758 | If xmktclapp.tcl shows an absolute pathname, then you |
||
| 759 | should give an absolute pathname when you "source" the |
||
| 760 | file. If the name in the listbox is relative, then the |
||
| 761 | argument to "source" must be relative. |
||
| 762 | Note also that case is significant. Even though |
||
| 763 | Windows will match names with differing case, mktclapp |
||
| 764 | uses the strcmp() function from the C library to compare |
||
| 765 | names, so the names really do have to be identical.</li></p> |
||
| 766 | |||
| 767 | <p><li> |
||
| 768 | Be sure that every file that you "source" really is listed |
||
| 769 | on the "Tcl Scripts" page. If a file isn't listed in |
||
| 770 | "Tcl Scripts" your program will fall back and read it from the disk |
||
| 771 | on your development machine. But when you move the program |
||
| 772 | to a different computer, that script won't be there anymore |
||
| 773 | and the program will fail. |
||
| 774 | |||
| 775 | <p>You can guard against this error by setting the Standalone |
||
| 776 | option on the "Settings" page to "Strict". In strict mode, |
||
| 777 | the "source" command of mktclapp will check for built-in files, |
||
| 778 | but if it doesn't find one it won't fall back to the disk. |
||
| 779 | Instead it just returns an error.</li></p> |
||
| 780 | |||
| 781 | <p><li> |
||
| 782 | Be sure to include your main script (the Tcl script that |
||
| 783 | runs first) both in the upper listbox and the lower entry |
||
| 784 | box on the "Tcl Scripts" page. It has to be in both places.</li></lp> |
||
| 785 | |||
| 786 | <p><li> |
||
| 787 | In order to conserve memory and run faster, mktclapp tries |
||
| 788 | to remove comments and extra whitespace from the Tcl scripts |
||
| 789 | before it compiles them into the program. But on some rare |
||
| 790 | occasions, these changes can break scripts. If you are having |
||
| 791 | problems, try turning off the comment removal and see if that |
||
| 792 | helps. To turn off comment removal for a particular script, |
||
| 793 | click on the script so that it is highlighted, then press |
||
| 794 | the "Don't Strip Comments" button.</li></p> |
||
| 795 | |||
| 796 | <p><li> |
||
| 797 | When you set Standalone to "Yes" or "Strict", the two Tcl/Tk |
||
| 798 | Library directories specified on the Libraries page of |
||
| 799 | xmktclapp.tcl must be compatible with each other and with |
||
| 800 | the Tcl/Tk C library that you link against. If this isn't |
||
| 801 | the case, the Tcl/Tk initialization will fail and your |
||
| 802 | program will not run. </li></p> |
||
| 803 | </ul> |
||
| 804 | |||
| 805 | <a name="addingccode"> |
||
| 806 | <a name="toc9"><!-- AUTO --> |
||
| 807 | <h2 align=center> |
||
| 808 | Adding In Some C Code |
||
| 809 | </h2> |
||
| 810 | |||
| 811 | <p>We've seen how to link Tcl/Tk scripts into your program. Now let's look |
||
| 812 | at how you can add in some C or C++ code.</p> |
||
| 813 | |||
| 814 | <p>As an example, create a C source code file named <b>hw.c</b> and |
||
| 815 | put in the following text. (Omit the line numbers. They are for |
||
| 816 | reference only.)</p> |
||
| 817 | |||
| 818 | <a name=code1> |
||
| 819 | <blockquote><pre> |
||
| 820 | <b>0001 /* A C module */ |
||
| 821 | 0002 #include <stdio.h> |
||
| 822 | 0003 #include "hello.h" |
||
| 823 | 0004 |
||
| 824 | 0005 int ET_COMMAND_print_hello(ET_TCLARGS){ |
||
| 825 | 0006 printf("Hello, out there!\n"); |
||
| 826 | 0007 return TCL_OK; |
||
| 827 | 0008 } |
||
| 828 | </b></pre></blockquote> |
||
| 829 | |||
| 830 | <p>To compile this C module into your program, bring up xmktclapp.tcl |
||
| 831 | again and go to the C/C++ Modules page. Click on the Insert button |
||
| 832 | and select "hw.c" from the menu. The C/C++ Modules pages should |
||
| 833 | look like figure 4.</p> |
||
| 834 | |||
| 835 | <p> |
||
| 836 | <a name=fig4> |
||
| 837 | <hr><center><img src="xmta-fig4.jpg" alt="Figure 4"><br> |
||
| 838 | <b>Figure 4</b></center><br><hr></p> |
||
| 839 | |||
| 840 | <p>Next return to the Settings page, press the "Build" button and |
||
| 841 | exit.</p> |
||
| 842 | |||
| 843 | <p>The C code in the hw.c file implements a new Tcl command named |
||
| 844 | <b>print_hello</b>. Adding the name of the C source code file |
||
| 845 | to the C/C++ Modules page of xmktclapp.tcl instructs mktclapp to |
||
| 846 | scan the source code looking for function definitions of the |
||
| 847 | the form</p> |
||
| 848 | |||
| 849 | <blockquote><pre> |
||
| 850 | <b>int ET_COMMAND_aaaaa(ET_TCLARGS){ |
||
| 851 | ... |
||
| 852 | return TCL_OK; |
||
| 853 | } |
||
| 854 | </b></pre></blockquote> |
||
| 855 | |||
| 856 | <p>where the string "aaaaa" in the function name can be any valid |
||
| 857 | C identifier. For every such function found, mktclapp will create |
||
| 858 | a new Tcl command named "aaaaa". And whenever that Tcl command |
||
| 859 | is invoked from within a script, the function will be called.</p> |
||
| 860 | |||
| 861 | <p>This is one of the primary means of communication between the |
||
| 862 | C/C++ side of your application and the Tcl/Tk scripts. Whenever |
||
| 863 | you want your Tcl/Tk script to execute some C code, you put the |
||
| 864 | C code inside a function whose name begins |
||
| 865 | with "ET_COMMAND_". The C code can then be executed by calling |
||
| 866 | the Tcl command whose name matches the suffix of the new C function.</p> |
||
| 867 | |||
| 868 | <p>In our example, we've created a new Tcl command named "print_hello", |
||
| 869 | but that command is never being called. Let's modify the "hello.tcl" |
||
| 870 | script a bit to change that. Edit hello.tcl so that it looks like |
||
| 871 | this:</p> |
||
| 872 | |||
| 873 | <blockquote><pre> |
||
| 874 | <b>button .b -text Go -command print_hello |
||
| 875 | button .e -text Quit -command exit |
||
| 876 | pack .b .e -side left |
||
| 877 | </b></pre></blockquote> |
||
| 878 | After making this edit, rerun xmktclapp.tcl and press the "Build" button |
||
| 879 | again in order to rebuild the application initialization module. |
||
| 880 | Then recompile everything as follows: |
||
| 881 | <blockquote><pre> |
||
| 882 | <b>gcc -o hello2 hw.c hello.c -ltk8.0 -ltcl8.0 -L/usr/X11R6/lib -lX11 -lm -ldl |
||
| 883 | </pre></b></blockquote> |
||
| 884 | |||
| 885 | <p>Notice that we now have to add the "hw.c" file to the compiler command |
||
| 886 | line. If you have a lot of C source files, it is probably best to |
||
| 887 | construct a Makefile that compiles each C modules separately then |
||
| 888 | links them all together in the end. Like this:</p> |
||
| 889 | |||
| 890 | <blockquote><pre> |
||
| 891 | <b>gcc -c hw.c |
||
| 892 | gcc -c hello.c |
||
| 893 | gcc -o hello hw.o hello.o -ltk8.0 -ltcl8.0 -L/usr/X11R6/lib -lX11 -lm -ldl |
||
| 894 | </pre></b></blockquote> |
||
| 895 | |||
| 896 | <p>That way, there is less to recompile if you make changes to a subset of |
||
| 897 | your C modules.</p> |
||
| 898 | |||
| 899 | <p>Now run the program. Click on the "Print" button and verify that the |
||
| 900 | message "Hello, out there!" is printed on standard output. |
||
| 901 | (Note that "printf" is a no-op on Windows. If you want to try |
||
| 902 | this example in Windows, you'll need to alter hw.c to write its |
||
| 903 | message to a file that you explicitly open instead of |
||
| 904 | writing to standard output.)</p> |
||
| 905 | |||
| 906 | <a name="toc10"><!-- AUTO --> |
||
| 907 | <h2 align=center> |
||
| 908 | Implementing New Tcl Commands In C |
||
| 909 | </h2> |
||
| 910 | |||
| 911 | <p>If you've never looked at Tcl's C API before, then you need to |
||
| 912 | take note of the interface details for a function that implements |
||
| 913 | a Tcl command. |
||
| 914 | The first thing to notice is that the function must return an |
||
| 915 | integer result code. |
||
| 916 | <a name="retcode"> |
||
| 917 | This result code must be one of the following values:</p> |
||
| 918 | |||
| 919 | <ul> |
||
| 920 | <p><li> <b>TCL_OK</b>. |
||
| 921 | This means the command completed successfully.</p> |
||
| 922 | |||
| 923 | <p><li> <b>TCL_ERROR</b>. |
||
| 924 | This means that an error occurred while executing the |
||
| 925 | command. In this case, the result string that is returned is |
||
| 926 | an error message describing what when wrong.</p> |
||
| 927 | |||
| 928 | <p><li> <b>TCL_RETURN</b>. |
||
| 929 | This means that the interpreter should immediately return |
||
| 930 | from the Tcl procedure it is currently executing. Returning this |
||
| 931 | value from a C function is the same as executing the <b>return</b> |
||
| 932 | command in Tcl.</p> |
||
| 933 | |||
| 934 | <p><li> <b>TCL_BREAK</b>. |
||
| 935 | This means that the interpreter should immediately exit |
||
| 936 | the inner-most loop that is currently active. This is the same as |
||
| 937 | executing the <b>break</b> command in Tcl.</p> |
||
| 938 | |||
| 939 | <p><li> <b>TCL_CONTINUE</b>. |
||
| 940 | This means that the interpreter should skip the rest of |
||
| 941 | the body of the inner-most loop and continue with the next iteration |
||
| 942 | of that loop. This is the same as the <b>continue</b> command in Tcl.</p> |
||
| 943 | </ul> |
||
| 944 | |||
| 945 | <p>In practice, you rarely ever use any but the first two values, |
||
| 946 | TCL_OK and TCL_ERROR. |
||
| 947 | All of these values are really integers. The symbolic |
||
| 948 | names given here are for C preprocessor macros that evaluate to the |
||
| 949 | appropriate integer. You should make it a habit to always use the |
||
| 950 | symbolic name rather than the raw integer value in your code. |
||
| 951 | The symbolic names are defined in the include file <tcl.h> which |
||
| 952 | is included by the header file that mktclapp generates. In the |
||
| 953 | code example <a href="#code1">above</a>, line 0003 includes the |
||
| 954 | header file that mktclapp generates and hence the <tcl.h> file gets |
||
| 955 | included and the symbolic names for the return values are defined.</p> |
||
| 956 | |||
| 957 | <p>The second thing to notice about C functions that implement Tcl commands |
||
| 958 | is that they require exactly four parameters, as follows:</p> |
||
| 959 | |||
| 960 | <ul> |
||
| 961 | <li> <b>ClientData clientData</b> |
||
| 962 | <li> <b>Tcl_Interp *interp</b> |
||
| 963 | <li> <b>int argc</b> |
||
| 964 | <li> <b>char **argv</b> |
||
| 965 | </ul> |
||
| 966 | |||
| 967 | <p>The <b>interp</b> parameter is a pointer to the Tcl interpreter. The |
||
| 968 | <b>argc</b> and <b>argv</b> parameters contain, respectively, the |
||
| 969 | number of arguments to the Tcl command and the text of each argument. |
||
| 970 | For Tcl commands created automatically by mktclapp, the <b>clientData</b> |
||
| 971 | parameter is always NULL.</p> |
||
| 972 | |||
| 973 | <p>It can be a chore to type in all four parameters |
||
| 974 | to every C function that implements a Tcl command. |
||
| 975 | Every such C function takes exactly the same four parameters. |
||
| 976 | So as a convenience, mktclapp supplies a macro named <b>ET_TCLARGS</b> |
||
| 977 | which contains the appropriate parameter definitions. Mktclapp |
||
| 978 | writes this macro into the header file it generates. In the case of our |
||
| 979 | example, the file is called <b>hello.h</b>. Notice again that we |
||
| 980 | include this file on line 0003 of the <a href="#code1">C code above</a> |
||
| 981 | so we are able to take the shortcut of using the macro.</p> |
||
| 982 | |||
| 983 | <p>The third important point about C functions that implement Tcl commands |
||
| 984 | is how they return their results. By default, a Tcl command will |
||
| 985 | return an empty string. But you can specify an different result using |
||
| 986 | one or more of the following Tcl API functions:</p> |
||
| 987 | |||
| 988 | <p><ul> |
||
| 989 | <li> <b>Tcl_SetResult</b> |
||
| 990 | <li> <b>Tcl_AppendResult</b> |
||
| 991 | <li> <b>Tcl_AppendElement</b> |
||
| 992 | <li> <b>Tcl_ResetResult</b> |
||
| 993 | </ul></p> |
||
| 994 | |||
| 995 | <p>The operation of these functions is well documented in the |
||
| 996 | Tcl manpages, and will not be repeated here.</p> |
||
| 997 | |||
| 998 | <p>Mktclapp provides another method for setting the return value of |
||
| 999 | a Tcl command that is sometimes easier to use than the standard |
||
| 1000 | Tcl API functions. This is the function named <b>Et_ResultF()</b>. |
||
| 1001 | The Et_ResultF function works very much like printf() from the |
||
| 1002 | standard C library. You give it a format string and a variable number |
||
| 1003 | of additional arguments whose values are substituted into specified |
||
| 1004 | places of the format string. But while printf() writes its result |
||
| 1005 | on standard output, Et_ResultF puts its result into the return value |
||
| 1006 | of the Tcl command.</p> |
||
| 1007 | |||
| 1008 | <p>An example will help to illustrate how Et_ResultF() works. Let's |
||
| 1009 | implement a Tcl command that adds the value of two arguments and |
||
| 1010 | returns the result. The file that will contain this new command |
||
| 1011 | will be <b>add.c</b>. The code looks like this:</p> |
||
| 1012 | |||
| 1013 | <blockquote><pre> |
||
| 1014 | <b>0001 /* Add two numbers and return the result */ |
||
| 1015 | 0002 #include "hello.h" |
||
| 1016 | 0003 |
||
| 1017 | 0004 int ET_COMMAND_add(ET_TCLARGS){ |
||
| 1018 | 0005 if( argc!=3 ){ |
||
| 1019 | 0006 Et_ResultF(interp, "wrong # args: should be \"%s NUM1 NUM2\"",argv[0]); |
||
| 1020 | 0007 return TCL_ERROR; |
||
| 1021 | 0008 } |
||
| 1022 | 0009 Et_ResultF(interp,"%d", atoi(argv[1]) + atoi(argv[2])); |
||
| 1023 | 0010 return TCL_OK; |
||
| 1024 | 0011 } |
||
| 1025 | </b></pre></blockquote> |
||
| 1026 | |||
| 1027 | <p>If you want to test this routine out, add the "add.c" file to the list |
||
| 1028 | of C/C++ Modules in xmktclapp.tcl, make some changes to "hello.tcl" that will |
||
| 1029 | call the new "add" Tcl command, and recompile. By now, you should be |
||
| 1030 | comfortable with doing this kind of thing, so we won't go into the details, |
||
| 1031 | but will instead focus on describing how the code works.</p> |
||
| 1032 | |||
| 1033 | <p>Line 0002 of add.c includes the header file that mktclapp generated for us. |
||
| 1034 | This header file contains a prototype for the Et_ResultF() function, and it |
||
| 1035 | includes the <tcl.h> header file so that we can access macros like |
||
| 1036 | TCL_OK and TCL_ERROR.</p> |
||
| 1037 | |||
| 1038 | <p>The implementation of the new "add" Tcl command is on lines 0004 through |
||
| 1039 | 0011. Lines 0005 through 0008 check to make sure the command is given |
||
| 1040 | exactly 2 arguments. Notice that we compare the argument count in |
||
| 1041 | <b>argc</b> to 3 instead of 2. That is because <b>argc</b> contains the |
||
| 1042 | number of arguments to the command, including the name of the command |
||
| 1043 | itself. If the number of arguments is not 2, then we will return an |
||
| 1044 | error condition (line 0007) but first we have to set the return value to |
||
| 1045 | be an appropriate error message. The call to Et_ResultF() on line |
||
| 1046 | 0006 does this. The first argument is a pointer to the Tcl interpreter. |
||
| 1047 | The second argument is a format string. Additional arguments are added |
||
| 1048 | as required by the format string.</p> |
||
| 1049 | |||
| 1050 | <p>If the number of arguments is correct, we fall through to lines 0009 and |
||
| 1051 | 0010. The return value is set by the Et_ResultF() call in line 0009. |
||
| 1052 | Since the command succeeded in this case, we return TCL_OK on line 0010.</p> |
||
| 1053 | |||
| 1054 | <a name="toc11"><!-- AUTO --> |
||
| 1055 | <h2 align=center> |
||
| 1056 | Using The Tcl_Obj Interface For Tcl New Commands |
||
| 1057 | </h2> |
||
| 1058 | |||
| 1059 | <p>Beginning with version 8.0, Tcl/Tk supports a new interface to commands |
||
| 1060 | that is faster in some circumstances. We won't go into the details |
||
| 1061 | of how the new interface works. (You can get that information from |
||
| 1062 | the Tcl/Tk documentation) |
||
| 1063 | But we would like to point out that mktclapp |
||
| 1064 | can create Tcl commands that use the new Tcl_Obj interface. |
||
| 1065 | All you have to do is preface the name of your function with |
||
| 1066 | ET_OBJCOMMAND instead of ET_COMMAND, and use ET_OBJARGS instead |
||
| 1067 | of ET_TCLARGS as the argument. So instead of</p> |
||
| 1068 | |||
| 1069 | <blockquote><pre> |
||
| 1070 | <b>int ET_COMMAND_print_hello(ET_TCLARGS){ |
||
| 1071 | printf("Hello, out there!\n"); |
||
| 1072 | return TCL_OK; |
||
| 1073 | } |
||
| 1074 | </b></pre></blockquote> |
||
| 1075 | |||
| 1076 | <p>write code like this:</p> |
||
| 1077 | |||
| 1078 | <blockquote><pre> |
||
| 1079 | <b>int ET_OBJCOMMAND_print_hello(ET_OBJARGS){ |
||
| 1080 | printf("Hello, out there!\n"); |
||
| 1081 | return TCL_OK; |
||
| 1082 | } |
||
| 1083 | </b></pre></blockquote> |
||
| 1084 | |||
| 1085 | <p>The new Tcl_Obj command interface is a little faster, but |
||
| 1086 | not that much faster. The big advantage to the Tcl_Obj interface |
||
| 1087 | is that it cleanly handles binary data. The main disadvantage is |
||
| 1088 | that the Tcl_Obj interface is harder to use. I recommend using |
||
| 1089 | the Tcl_Obj interface only for commands that deal with binary data |
||
| 1090 | and continuing to use the older string interface for all other |
||
| 1091 | commands.</p> |
||
| 1092 | |||
| 1093 | <a name="toc12"><!-- AUTO --> |
||
| 1094 | <h2 align=center> |
||
| 1095 | Using Tcl Namespaces |
||
| 1096 | </h2> |
||
| 1097 | |||
| 1098 | <p>The names of C functions may contain only alphanumeric and |
||
| 1099 | underscore characters. But in order to generate a Tcl command in |
||
| 1100 | a namespace, you need to embed colons in the name. |
||
| 1101 | To accomodate this, whenever mktclapp sees an ET_COMMAND_ function |
||
| 1102 | name that contains two underscores in a row, it changes both |
||
| 1103 | underscores to colons in the corresponding Tcl command. |
||
| 1104 | This allows you to create new Tcl commands in a namespace.</p> |
||
| 1105 | |||
| 1106 | <p>For example, suppose you wanted to created a new Tcl command |
||
| 1107 | named <b>ns1::func1</b>. Your C code would look something like |
||
| 1108 | this:</p> |
||
| 1109 | |||
| 1110 | <blockquote><pre> |
||
| 1111 | <b>int ET_COMMAND_ns1__func1(ET_TCLARGS){ |
||
| 1112 | ... |
||
| 1113 | return TCL_OK; |
||
| 1114 | } |
||
| 1115 | </b></pre></blockquote> |
||
| 1116 | |||
| 1117 | <p>The two underscores between "ns1" and "func1" in the C function |
||
| 1118 | name will be converted into colons for the corresponding Tcl command, |
||
| 1119 | thus giving the desired result.</p> |
||
| 1120 | |||
| 1121 | <a name="toc13"><!-- AUTO --> |
||
| 1122 | <h2 align=center> |
||
| 1123 | Executing Tcl/Tk Commands From C Code |
||
| 1124 | </h2> |
||
| 1125 | |||
| 1126 | <p>The previous sections described how you can transfer control from |
||
| 1127 | Tcl/Tk over to C. Now let's see how to go the other direction: how |
||
| 1128 | to execute Tcl/Tk code from within a C function.</p> |
||
| 1129 | |||
| 1130 | <p>The Tcl API provides several functions that will cause a string |
||
| 1131 | to be interpreted as a Tcl/Tk script. We find:</p> |
||
| 1132 | |||
| 1133 | <p><ul> |
||
| 1134 | <li> <b>Tcl_Eval</b> |
||
| 1135 | <li> <b>Tcl_VarEval</b> |
||
| 1136 | <li> <b>Tcl_GlobalEval</b> |
||
| 1137 | <li> <b>Tcl_EvalFile</b> |
||
| 1138 | </ul></p> |
||
| 1139 | |||
| 1140 | <p>All of these functions are fully documented by the Tcl manpages, |
||
| 1141 | so we won't go into a lot of detail here about how they work. But |
||
| 1142 | a quick example won't hurt.</p> |
||
| 1143 | |||
| 1144 | <p>Consider the Tcl_Eval() function. This function takes two argument. |
||
| 1145 | <ol> |
||
| 1146 | <li> A pointer to a Tcl interpreter, and |
||
| 1147 | <li> A string that contains Tcl code to be executed. |
||
| 1148 | </ol> |
||
| 1149 | The Tcl_Eval() function returns an integer which is one of the |
||
| 1150 | return codes (TCL_OK, TCL_ERROR, etc.) described |
||
| 1151 | <a href="#retcode">above.</a>. The way Tcl_Eval() works is |
||
| 1152 | this: it breaks up the string you give it into one or more |
||
| 1153 | Tcl commands. It parses each command up into a command name |
||
| 1154 | and its arguments. It then calls a C function to execute that |
||
| 1155 | command. If the C function returns TCL_OK, then Tcl_Eval() procedes |
||
| 1156 | to execute the next command in the sequence. And so forth until |
||
| 1157 | all commands have been executed. But if any implementation |
||
| 1158 | function returns something other than TCL_OK, the commands |
||
| 1159 | that follow are skipped and Tcl_Eval() returns immediately. |
||
| 1160 | The return code of Tcl_Eval() is always the return code of |
||
| 1161 | the last command executed. The result of the last Tcl |
||
| 1162 | command executed (or the error message if TCL_ERROR is returned) |
||
| 1163 | is stored in <b>interp->result</b> where <b>interp</b> is the |
||
| 1164 | pointer to the Tcl interpreter.</p> |
||
| 1165 | |||
| 1166 | <p>We will illustrate the use of Tcl_Eval() by implementing a Tcl |
||
| 1167 | command in C that invokes another Tcl command as part of its |
||
| 1168 | execution. Call our example command <b>factor</b>. It has |
||
| 1169 | two argument.</p> |
||
| 1170 | |||
| 1171 | <blockquote> |
||
| 1172 | <b>factor</b> <i>NUMBER PROC</i> |
||
| 1173 | </blockquote> |
||
| 1174 | |||
| 1175 | <p>The factor command will compute all factors of <i>NUMBER</i> and |
||
| 1176 | for each factor <i>F</i> it will invoke the Tcl procedure |
||
| 1177 | named <i>PROC</i> with a single argument <i>F</i>. |
||
| 1178 | So, for example, if we execute the command</p> |
||
| 1179 | |||
| 1180 | <blockquote><pre> |
||
| 1181 | <b>factor 12 puts</b> |
||
| 1182 | </pre></blockquote> |
||
| 1183 | |||
| 1184 | <p>the implementation of factor will invoke the <b>puts</b> Tcl command |
||
| 1185 | six times, once each with the arguments "1", "2", "3", "4", "6" and "12".</p> |
||
| 1186 | |||
| 1187 | <a name=code2> |
||
| 1188 | <blockquote><pre> |
||
| 1189 | <b>0001 /* Implementation of the factor command */ |
||
| 1190 | 0002 #include "hello.h" |
||
| 1191 | 0003 |
||
| 1192 | 0004 int ET_COMMAND_factor(ET_TCLARGS){ |
||
| 1193 | 0005 int i, n; |
||
| 1194 | 0006 char *zCmd; |
||
| 1195 | 0007 if( argc!=3 ){ |
||
| 1196 | 0008 Et_ResultF(interp,"wrong # args: should be \"%s NUM PROC\"",argv[0]); |
||
| 1197 | 0009 return TCL_ERROR; |
||
| 1198 | 0010 } |
||
| 1199 | 0011 zCmd = Tcl_Alloc( strlen(argv[2]) + 100 ); |
||
| 1200 | 0012 if( zCmd==0 ){ |
||
| 1201 | 0013 Et_ResultF(interp,"out of memory"); |
||
| 1202 | 0014 return TCL_ERROR; |
||
| 1203 | 0015 } |
||
| 1204 | 0016 n = atoi(argv[1]); |
||
| 1205 | 0017 for(i=1; i<=n; i++){ |
||
| 1206 | 0018 if( (n/i)*i!=n ) continue; |
||
| 1207 | 0019 sprintf(zCmd, "%s %d", argv[2], i); |
||
| 1208 | 0020 if( Tcl_Eval(interp, zCmd)!=TCL_OK ){ |
||
| 1209 | 0021 Tcl_Free(zCmd); |
||
| 1210 | 0022 return TCL_ERROR; |
||
| 1211 | 0023 } |
||
| 1212 | 0024 } |
||
| 1213 | 0025 Tcl_Free(zCmd); |
||
| 1214 | 0026 return TCL_OK; |
||
| 1215 | 0027 } |
||
| 1216 | </b></pre></blockquote> |
||
| 1217 | |||
| 1218 | <p>Let's have a look at the code. We begin, as always, by including |
||
| 1219 | the necessary header files on line 0002. The rest of the code is |
||
| 1220 | an implementation of the "factor" Tcl command on lines 0004 through |
||
| 1221 | 0027. The first thing the factor command does is make sure it was |
||
| 1222 | called with exactly two arguments. If not, an error message is |
||
| 1223 | created and the function returns with an error. Next, on line 0011, |
||
| 1224 | we allocate space to hold the Tcl commands that we will execute for |
||
| 1225 | each factor. We have to dynamically allocate this space, since we |
||
| 1226 | cannot know in advance how big the name of the callback procedure |
||
| 1227 | will be. The Tcl library imposes no length limitations on |
||
| 1228 | strings and you should strive to do the same with the |
||
| 1229 | code you add.</p> |
||
| 1230 | |||
| 1231 | <p>The loop from lines 0017 to 0024 iterates over all values between |
||
| 1232 | 1 and the target number, and line 0018 discards those that are |
||
| 1233 | not factors. (This is not a very efficient way to compute the |
||
| 1234 | factors of a number, by the way. But a better |
||
| 1235 | algorithm would require considerably more code which would obsure |
||
| 1236 | the point of the example.) On line 0019, we construct the text of |
||
| 1237 | a Tcl command to execute for the single factor in the variable <b>i</b>. |
||
| 1238 | Then the command is executed using Tcl_Eval on line 0020. Notice |
||
| 1239 | that we test to make sure Tcl_Eval returns TCL_OK, and we abort |
||
| 1240 | immediately if it does not. Finally, after the loop exits, we |
||
| 1241 | free the dynamically allocated memory and return successfully.</p> |
||
| 1242 | |||
| 1243 | <p>You will notice in this example that a considerable amount of code |
||
| 1244 | was used to dynamically allocate space for the Tcl command that |
||
| 1245 | was to be executed. A lot of this extra could can be avoided by |
||
| 1246 | using a special function provided by mktclapp that does the same |
||
| 1247 | work as Tcl_Eval, but with more flexible calling parameters. |
||
| 1248 | The <b>Et_EvalF</b> function executes Tcl code like Tcl_Eval, but |
||
| 1249 | it constructs the Tcl code using printf-style arguments. Take |
||
| 1250 | a look at the same "factor" command coded using Et_EvalF instead |
||
| 1251 | of Tcl_Eval:</p> |
||
| 1252 | |||
| 1253 | <a name=code3> |
||
| 1254 | <blockquote><pre> |
||
| 1255 | <b>0001 /* Implementation of the factor command */ |
||
| 1256 | 0002 #include "hello.h" |
||
| 1257 | 0003 |
||
| 1258 | 0004 int ET_COMMAND_factor(ET_TCLARGS){ |
||
| 1259 | 0005 int i, n; |
||
| 1260 | 0006 if( argc!=3 ){ |
||
| 1261 | 0007 Et_ResultF(interp,"wrong # args: should be \"%s NUM PROC\"",argv[0]); |
||
| 1262 | 0008 return TCL_ERROR; |
||
| 1263 | 0009 } |
||
| 1264 | 0010 n = atoi(argv[1]); |
||
| 1265 | 0011 for(i=1; i<=n; i++){ |
||
| 1266 | 0012 if( (n/i)*i!=n ) continue; |
||
| 1267 | 0013 if( Et_EvalF(interp, "%s %d", argv[2], i)!=TCL_OK ){ |
||
| 1268 | 0014 return TCL_ERROR; |
||
| 1269 | 0015 } |
||
| 1270 | 0016 } |
||
| 1271 | 0017 return TCL_OK; |
||
| 1272 | 0018 } |
||
| 1273 | </b></pre></blockquote> |
||
| 1274 | |||
| 1275 | <p>What a difference! The use of Et_EvalF reduced the size of the |
||
| 1276 | factor command by one third. It also helped reduce |
||
| 1277 | the danger of memory leaks that would result if (for example) line |
||
| 1278 | 0021 were accidently omitted from the Tcl_Eval implementation. Et_EvalF |
||
| 1279 | executes Tcl code in the same way as Tcl_Eval, but with a much more |
||
| 1280 | convenient interface. Experience with Et_EvalF shows |
||
| 1281 | it can greatly decrease coding effort and the number of coding errors.</p> |
||
| 1282 | |||
| 1283 | <a name="toc14"><!-- AUTO --> |
||
| 1284 | <h2 align=center> |
||
| 1285 | Other Functions Provided By Mktclapp |
||
| 1286 | </h2> |
||
| 1287 | |||
| 1288 | <p>We've already seen two functions that are provided by mktclapp that |
||
| 1289 | do not appear in the standard Tcl library: <b>Et_ResultF</b> and |
||
| 1290 | <b>Et_EvalF</b>. There are others which haven't been mentioned.</p> |
||
| 1291 | |||
| 1292 | <ul> |
||
| 1293 | <li> <p><b>Et_GlobalEvalF</b>. |
||
| 1294 | This works just like Et_EvalF, except that all variables are evaluated |
||
| 1295 | in the global context. Et_GlobalEvalF is to Et_EvalF what |
||
| 1296 | Tcl_GlobalEval is to Tcl_Eval.</p> |
||
| 1297 | |||
| 1298 | <li> <p><b>Et_DStringAppendF</b>. |
||
| 1299 | This routine works like Tcl_DStringAppend with the addition that the |
||
| 1300 | string to be appended is constructed using printf-style arguments. |
||
| 1301 | For more information on what Tcl_DStringAppend does, refer to the |
||
| 1302 | Tcl manpages.</p> |
||
| 1303 | |||
| 1304 | <li> <p><b>mprintf</b>. |
||
| 1305 | This helpful routine works like the <b>sprintf</b> routine from the |
||
| 1306 | standard C library. Except, instead of taking the buffer into which |
||
| 1307 | the results are written as its first parameter, the mprintf routine |
||
| 1308 | mallocs for sufficient space to hold the result and returns a pointer |
||
| 1309 | to the malloced space. The calling function is responsible for |
||
| 1310 | freeing the memory to avoid a memory leak. |
||
| 1311 | This implementation of mprintf actually |
||
| 1312 | uses Tcl_Alloc to obtain its memory, so the memory really should |
||
| 1313 | be freed by calling Tcl_Free. Tcl_Alloc and Tcl_Free are fully |
||
| 1314 | documented in the Tcl manpages.</p> |
||
| 1315 | |||
| 1316 | <li> <p><b>vmprintf</b>. |
||
| 1317 | This is a varargs version of mprintf().</p> |
||
| 1318 | </ul> |
||
| 1319 | |||
| 1320 | <p>In addition to these function, mktclapp also provides a global variable |
||
| 1321 | named <b>Et_Interp</b> which is a pointer to the main Tcl interpreter |
||
| 1322 | for your application. A pointer to an interpreter is required as the |
||
| 1323 | first parameter to many routines in the Tcl library, as well as to |
||
| 1324 | mktclapp routines like Et_EvalF. If your program only uses a single |
||
| 1325 | Tcl interpreter (most programs fulfill this constraint) then you can |
||
| 1326 | use the global variable <b>Et_Interp</b> rather than pass a |
||
| 1327 | pointer to the interpreter as a parameter to every C subroutine you |
||
| 1328 | write.</p> |
||
| 1329 | |||
| 1330 | <a name="toc15"><!-- AUTO --> |
||
| 1331 | <h2 align=center> |
||
| 1332 | The <tt>%q</tt> Format Field |
||
| 1333 | </h2> |
||
| 1334 | |||
| 1335 | <p>There is subtle danger in using the <b>%s</b> format field within |
||
| 1336 | the Et_EvalF function and its kin. Consider what would happen if |
||
| 1337 | the string that is inserted in place of the %s contains characters |
||
| 1338 | with special meaning to Tcl.</p> |
||
| 1339 | |||
| 1340 | <p>For example, suppose you have a Tcl/Tk command named <b>PopupMessage</b> |
||
| 1341 | that takes a text string as its only argument and displays that string |
||
| 1342 | as a message in a popup dialog box. If the your C code frequently |
||
| 1343 | needs to pop up messages, you might consider writing a C subroutine |
||
| 1344 | to do the work for you, like this:</p> |
||
| 1345 | |||
| 1346 | <blockquote><pre> |
||
| 1347 | <b>void DoPopup(const char *zMsg){ |
||
| 1348 | Et_EvalF(Et_Interp,"PopupMessage \"%s\"", zMsg); |
||
| 1349 | } |
||
| 1350 | </b></pre></blockquote> |
||
| 1351 | |||
| 1352 | <p>If you invoke this subroutine with a message that read |
||
| 1353 | "Hello, World!", then the Et_EvalF function would construct |
||
| 1354 | a Tcl command that said</p> |
||
| 1355 | |||
| 1356 | <blockquote><pre> |
||
| 1357 | <b>PopupMessage "Hello, World!" |
||
| 1358 | </b></pre></blockquote> |
||
| 1359 | |||
| 1360 | <p>which would do what you intend. But now consider what would happen |
||
| 1361 | if you invoke DoPopup with a string like this:</p> |
||
| 1362 | |||
| 1363 | <blockquote><pre> |
||
| 1364 | <b>DoPopup("Missing \";\" on line 11"); |
||
| 1365 | </b></pre></blockquote> |
||
| 1366 | |||
| 1367 | <p>In this case, Et_EvalF would construct its Tcl command to read |
||
| 1368 | as follows:</p> |
||
| 1369 | |||
| 1370 | <blockquote><pre> |
||
| 1371 | <b>PopupMessage "Missing ";" on line 11" |
||
| 1372 | </b></pre></blockquote> |
||
| 1373 | |||
| 1374 | <p>And this command will not work. The Tcl interpreter will break |
||
| 1375 | this string into two commands. The first command will invoke |
||
| 1376 | the PopupMessage procedure with the string "Missing ", and the |
||
| 1377 | second command will consist of the text " on line 11". Certainly |
||
| 1378 | not what you intended.</p> |
||
| 1379 | |||
| 1380 | <p>You might try to work around this problem by using curly braces |
||
| 1381 | rather than double quotes to enclose the argument to PopupMessage, |
||
| 1382 | like this:</p> |
||
| 1383 | |||
| 1384 | <blockquote><pre> |
||
| 1385 | <b>void DoPopup(const char *zMsg){ |
||
| 1386 | Et_EvalF(Et_Interp,"PopupMessage {%s}", zMsg); |
||
| 1387 | } |
||
| 1388 | </b></pre></blockquote> |
||
| 1389 | |||
| 1390 | <p>This changes the problem, but does not make it go away. Now the |
||
| 1391 | function fails when the input string is something like</p> |
||
| 1392 | |||
| 1393 | <blockquote><pre> |
||
| 1394 | <b>DoPopup("Missing \"}\" on line 11"); |
||
| 1395 | </b></pre></blockquote> |
||
| 1396 | |||
| 1397 | <p>The solution to this conundrum is to never use the %s format |
||
| 1398 | directive when the string to be inserted can possibly contain |
||
| 1399 | characters that are special to Tcl. Et_EvalF provides an |
||
| 1400 | alternative formatting directived called <b>%q</b> (the "q" stands |
||
| 1401 | for "quote") that works just like %s except that it inserts a |
||
| 1402 | backslash character before every character in the inserted string |
||
| 1403 | that has special meaning to Tcl. So what we have to do is |
||
| 1404 | change the DoPopup function to read as follows:</p> |
||
| 1405 | |||
| 1406 | <blockquote><pre> |
||
| 1407 | <b>void DoPopup(const char *zMsg){ |
||
| 1408 | Et_EvalF(Et_Interp,"PopupMessage \"%q\"", zMsg); |
||
| 1409 | } |
||
| 1410 | </b></pre></blockquote> |
||
| 1411 | |||
| 1412 | <p>Now when the DoPopup function is called with an input string |
||
| 1413 | that contains special characters, like this:</p> |
||
| 1414 | |||
| 1415 | <blockquote><pre> |
||
| 1416 | <b>DoPopup("Missing \";\" on line 11"); |
||
| 1417 | </b></pre></blockquote> |
||
| 1418 | |||
| 1419 | <p>the Tcl command that Et_EvalF constructs reads as follows:</p> |
||
| 1420 | |||
| 1421 | <blockquote><pre> |
||
| 1422 | <b>PopupMessage "Missing \";\" on line 11" |
||
| 1423 | </b></pre></blockquote> |
||
| 1424 | |||
| 1425 | <p>The Et_EvalF function has inserted a backslash before each double-quote |
||
| 1426 | character in the string. |
||
| 1427 | This Tcl command gives the intended result.</p> |
||
| 1428 | |||
| 1429 | <p>The %q formatting directive is available in all of the extension |
||
| 1430 | functions provided by mktclapp: Et_EvalF, Et_ResultF, Et_GlobalEvalF, |
||
| 1431 | Et_DStringAppendF, mprintf, and vmprintf. |
||
| 1432 | Some general guidelines on how and when to use %q instead of %s |
||
| 1433 | follow:</p> |
||
| 1434 | |||
| 1435 | <ul> |
||
| 1436 | <li> <p>Always use %q for strings whose content can be influenced by |
||
| 1437 | the user or by input data. To do otherwise will open security |
||
| 1438 | holes in your program.</p> |
||
| 1439 | |||
| 1440 | <li> <p>Use %q rather than %s for any string that might contain characters |
||
| 1441 | that are special to Tcl.</p> |
||
| 1442 | |||
| 1443 | <li> <p>The %q formatter does not escape spaces, so it is best to put you |
||
| 1444 | %q inside of double-quotes.</p> |
||
| 1445 | |||
| 1446 | <li> <p>%q is designed for use within double-quotes, not curly braces. |
||
| 1447 | Use the %q like this: <b>\"%q\"</b> Not like this: <b>{%q}</b>.</p> |
||
| 1448 | |||
| 1449 | </ul> |
||
| 1450 | |||
| 1451 | <a name="toc16"><!-- AUTO --> |
||
| 1452 | <h2 align=center> |
||
| 1453 | Putting A <tt>main()</tt> In Your C Code |
||
| 1454 | </h2> |
||
| 1455 | |||
| 1456 | <p>Every C program requires a <b>main()</b> function. If you don't |
||
| 1457 | supply one in the C code you link with mktclapp, then mktclapp will |
||
| 1458 | put its own main() in the application initialization module that |
||
| 1459 | it builds. |
||
| 1460 | This is the recommended practice. |
||
| 1461 | But for special circumstances, you may want to provide your own |
||
| 1462 | main() function. |
||
| 1463 | That's fine. The code that mktclapp generates will still work. |
||
| 1464 | But you need to remember two things:</p> |
||
| 1465 | |||
| 1466 | <ol> |
||
| 1467 | <li> <p>At some point, you need to call the routine <b>Et_Init()</b> |
||
| 1468 | and pass it the value of <b>argc</b> and <b>argv</b> from |
||
| 1469 | main(), in order to initialize the Tcl/Tk interpreter. |
||
| 1470 | Your code might look something like this:</p> |
||
| 1471 | |||
| 1472 | <blockquote><pre> |
||
| 1473 | <b>int main(int argc, argv){ |
||
| 1474 | /* Your code goes here */ |
||
| 1475 | Et_Init(argc, argv); |
||
| 1476 | return 0; |
||
| 1477 | } |
||
| 1478 | </b></pre></blockquote> |
||
| 1479 | |||
| 1480 | <p>The Et_Init() function doesn't return until the Tcl/Tk interpreter |
||
| 1481 | has been terminated. For a GUI application, this means it |
||
| 1482 | never returns. So don't put any code after your call to |
||
| 1483 | Et_Init() that you want to execute.</p> |
||
| 1484 | |||
| 1485 | <li> <p>The "Fork Into Background" feature that can be optionally |
||
| 1486 | enabled using mktclapp will not work if you supply your own |
||
| 1487 | main() routine.</p> |
||
| 1488 | </ol> |
||
| 1489 | |||
| 1490 | <a name="appinit"> |
||
| 1491 | <a name="toc17"><!-- AUTO --> |
||
| 1492 | <h2 align=center> |
||
| 1493 | C Functions For Application Initialization |
||
| 1494 | </h2> |
||
| 1495 | |||
| 1496 | <p>If the C code that you link using mktclapp contains a function |
||
| 1497 | named <b>Et_AppInit()</b>, then that function will be called right |
||
| 1498 | after the Tcl/Tk interpreter has been initialized. So if you need |
||
| 1499 | to do any additional setup to the Tcl/Tk interpreter, such |
||
| 1500 | as loading an extension, the Et_AppInit() function |
||
| 1501 | is a great place to do it.</p> |
||
| 1502 | |||
| 1503 | <p>For example, suppose you need to include the BLT extensions in |
||
| 1504 | your application. You could simply add C code that looks |
||
| 1505 | like the following:</p> |
||
| 1506 | |||
| 1507 | <blockquote><pre> |
||
| 1508 | <b>0001 #include "appinit.h" |
||
| 1509 | 0002 #include <blt.h> |
||
| 1510 | 0003 |
||
| 1511 | 0004 int Et_AppInit(Tcl_Interp *interp){ |
||
| 1512 | 0005 Blt_Init(interp); |
||
| 1513 | 0006 return TCL_OK; |
||
| 1514 | 0007 } |
||
| 1515 | </b></pre></blockquote> |
||
| 1516 | |||
| 1517 | <p>Let's look more closely at this code. Line 0001 sources the header |
||
| 1518 | file that mktclapp generates. (Depending on what name you choose for |
||
| 1519 | the generated files, you might need to alter this line.) We also |
||
| 1520 | need to include the header file for BLT on line 0002. The implementation |
||
| 1521 | of Et_AppInit begins on line 0004. Notice that it takes a single parameter |
||
| 1522 | which is a pointer to the Tcl interpreter and returns an integer. |
||
| 1523 | On Line 0005, the BLT extension is initialized. Finally on line |
||
| 1524 | 0006 we return from Et_AppInit(). Notice the Et_AppInit() should |
||
| 1525 | return TCL_OK if there were no errors.</p> |
||
| 1526 | |||
| 1527 | <p>Other Tcl/Tk extensions are initialized in a similar way. To initialize |
||
| 1528 | an extension named <b>ABC</b> you typically invoke a function named |
||
| 1529 | <b>Abc_Init(interp)</b> inside of Et_AppInit(). Refer to the |
||
| 1530 | documentation for the particular extension you want to initialize for |
||
| 1531 | details. Some Tcl/Tk extensions (such as TclX) include additional |
||
| 1532 | Tcl Script files that must be loaded with the application in order |
||
| 1533 | for the application to run standalone. For these extensions, you |
||
| 1534 | will need to list those script files on the "Tcl Scripts" page of |
||
| 1535 | xmktclapp.tcl so that they will be compiled into the initialization module. |
||
| 1536 | Or (beginning with version 3.0 of mktclapp) you can list the directories |
||
| 1537 | containing the extra scripts in the "Other Libraries" entry field on |
||
| 1538 | the "Libraries" page of xmktclapp.tcl. I'm told that you might also |
||
| 1539 | need to make some change to the "auto_path" variable in order to |
||
| 1540 | get Tix and IncrTcl to work right. But the only major extension I ever |
||
| 1541 | use is BLT, so I can not say from personal experience.</p> |
||
| 1542 | |||
| 1543 | <p>The Et_AppInit() function is also a convenient place in which to |
||
| 1544 | make calls the the <b>Tcl_LinkVar</b> function in order to create |
||
| 1545 | a link between Tcl variables and C variables. Refer to the documentation |
||
| 1546 | of the Tcl_LinkVar() function for additional information.</p> |
||
| 1547 | |||
| 1548 | <p>In addition to Et_AppInit(), the code generated by mktclapp will |
||
| 1549 | also call a function named <b>Et_PreInit()</b> if it is present. |
||
| 1550 | The difference between Et_AppInit() and Et_PreInit() is this: |
||
| 1551 | Et_PreInit() is called before the core Tcl/Tk modules are initialized, |
||
| 1552 | but Et_AppInit() is called afterwards. It is very unusual to need |
||
| 1553 | to use Et_PreInit(). If you do not clearly understand the difference, |
||
| 1554 | it is safer to stick with Et_AppInit().</p> |
||
| 1555 | |||
| 1556 | <a name="toc17a"><!-- AUTO --> |
||
| 1557 | <h2 align=center> |
||
| 1558 | Bundling Binary Data Files With The Executable |
||
| 1559 | </h2> |
||
| 1560 | |||
| 1561 | <p>The principal magic of mktclapp is that it compiles your Tcl scripts |
||
| 1562 | into the executable as static character strings. Beginning with version |
||
| 1563 | 3.8 of mktclapp, you can do the same thing with binary data files, such |
||
| 1564 | as GIFs. Just add the name of each data file you want to insert on the |
||
| 1565 | Data Files page of the application wizard and mktclapp will add the contents |
||
| 1566 | of each file to the executable as an array of characters. You can access |
||
| 1567 | the data file using the normal file access commands of Tcl.</p> |
||
| 1568 | |||
| 1569 | <p>As an example, suppose you have the following Tcl/Tk code |
||
| 1570 | in a file named <b>ckmail.tcl</b>:</p> |
||
| 1571 | |||
| 1572 | <blockquote><pre> |
||
| 1573 | <b>image create photo mailicon -file mailicon.gif |
||
| 1574 | button .b -image mailicon -command {exec checkmail &} |
||
| 1575 | pack .b</b> |
||
| 1576 | </pre></blockquote> |
||
| 1577 | |||
| 1578 | <p>This program shows a single button containing a GIF icon where the |
||
| 1579 | GIF is loaded from a separate file <b>mailicon.gif</b>. To turn this |
||
| 1580 | script into a standalone program using mktclapp, bring up xmktclapp.tcl |
||
| 1581 | and enter the ckmail.tcl script in two places on the Tcl Scripts page. |
||
| 1582 | Then go over to the Data Files pages of xmktclapp.tcl and enter |
||
| 1583 | the name of the GIF icon. Like this:</p> |
||
| 1584 | |||
| 1585 | <p><center> |
||
| 1586 | <img src="xmta-fig6.jpg" alt="unnumbered figure"> |
||
| 1587 | </center><p> |
||
| 1588 | |||
| 1589 | <p>Then select File/Build from the menu and exit xmktclapp.tcl. |
||
| 1590 | Mktclapp will include both |
||
| 1591 | the Tcl script ckmail.tcl and the image mailicon.gif in the |
||
| 1592 | generated application initialization file (<b>ckmail.c</b>). |
||
| 1593 | All you have to do now is compile that file.</p> |
||
| 1594 | |||
| 1595 | <blockquote><pre> |
||
| 1596 | <b>gcc -o ckmail ckmail.c -ltk8.0 -L/usr/X11R6/lib -lX11 -ltcl8.0 -lm -ldl</b> |
||
| 1597 | </pre></blockquote> |
||
| 1598 | |||
| 1599 | <p>The ability to access data files as if they were normal files on |
||
| 1600 | the disk depends on certain API functions that appeared in Tcl beginning |
||
| 1601 | with release 8.0.3. So this feature will not work if you are using an |
||
| 1602 | earlier version of Tcl.</p> |
||
| 1603 | |||
| 1604 | <a name="toc17b"><!-- AUTO --> |
||
| 1605 | <h2 align=center> |
||
| 1606 | Building Tcl Extensions Using Mktclapp |
||
| 1607 | </h2> |
||
| 1608 | |||
| 1609 | <p>Another new feature to mktclapp as of version 3.8 is the ability to |
||
| 1610 | generate an application initialization file that works as a Tcl extension |
||
| 1611 | rather than as a standalone program. To build a Tcl extension, enter |
||
| 1612 | the names of C/C++ modules, Tcl scripts, and Data Files into xmktclapp.tcl |
||
| 1613 | as you normally would. But on the Settings page select <b>Extension</b> |
||
| 1614 | for the Application Mode. Then select File/Build from the menu. |
||
| 1615 | Assuming the name of the generated application initialization file is |
||
| 1616 | <b>hello.c</b>, you can compile the extension for Unix as follows:</p> |
||
| 1617 | |||
| 1618 | <blockquote><pre> |
||
| 1619 | <b>gcc -shared -o hello.so hello.c -ltk -L/usr/X11R6/lib -lX11 -ltcl -lm -ldl |
||
| 1620 | </b></pre></blockquote> |
||
| 1621 | |||
| 1622 | <p>For Windows, the compilation process is more involved. These are |
||
| 1623 | the steps:</p> |
||
| 1624 | |||
| 1625 | <blockquote><pre> |
||
| 1626 | <b>gcc -c hello.c |
||
| 1627 | echo EXPORTS >hello.def |
||
| 1628 | echo Hello_Init >>hello.def |
||
| 1629 | dllwrap --def hello.def -v --export-all -dllname hello.dll \ |
||
| 1630 | hello.o -ltk -ltcl</b> |
||
| 1631 | </pre></blockquote> |
||
| 1632 | |||
| 1633 | <p>The above will generate an extension that can be loaded only by |
||
| 1634 | the <b>cygwish</b> version of wish that comes with Cygwin. If you |
||
| 1635 | want to make the extension usable by any version of wish, you have |
||
| 1636 | to enable stubs support. Do so by adding the options |
||
| 1637 | "-DUSE_TCL_STUBS" and "-mno-cygwin" to the compiler command line and |
||
| 1638 | link against a compatible Tcl stubs library. You'll have to build a |
||
| 1639 | version of the |
||
| 1640 | stubs libraries that is compatible with cygwin in order for this |
||
| 1641 | to work. The sources to this library are in files named <b>tclStubLib.c</b> |
||
| 1642 | and <b>tkStubLib.c</b> in the Tcl/Tk source tree.</p> |
||
| 1643 | |||
| 1644 | <p>The name of the initialization function within the generated extension |
||
| 1645 | is based on the name of the initialization file. In the example above, |
||
| 1646 | the initialization file was named <b>hello.c</b> so the initialization |
||
| 1647 | function for the extension will be named <b>Hello_Init</b>. The initialization |
||
| 1648 | function name is formed by taking the root name of the initialization file, |
||
| 1649 | making the first letter upper case and all other letters lower case, and |
||
| 1650 | appending "_Init".</p> |
||
| 1651 | |||
| 1652 | <p>You can compile Tcl scripts and Data Files into your extension just |
||
| 1653 | like you can with standalone applications. If your extension contains |
||
| 1654 | an Et_AppInit() function, that function will be executed as soon as the |
||
| 1655 | extension is loaded. If you specify a Startup Script, the script will |
||
| 1656 | be executed when the extension is loaded, right after the Et_AppInit() |
||
| 1657 | function has run.</p> |
||
| 1658 | |||
| 1659 | <a name="toc18"><!-- AUTO --> |
||
| 1660 | <h2 align=center> |
||
| 1661 | Running Mktclapp From The Command Line<br> |
||
| 1662 | Or In A Makefile |
||
| 1663 | </h2> |
||
| 1664 | |||
| 1665 | <p>The xmktclapp.tcl GUI really just collects data. The |
||
| 1666 | mktclapp command-line program is what does all the work. |
||
| 1667 | So if you want to fully understand mktclapp, you have to |
||
| 1668 | understand what the command-line program does.</p> |
||
| 1669 | |||
| 1670 | <p>The mktclapp command line program is what generates both |
||
| 1671 | the application initialization code and the corresponding |
||
| 1672 | header file. Mktclapp is controlled completely by command-line |
||
| 1673 | arguments. Its output appears on standard output.</p> |
||
| 1674 | |||
| 1675 | <p>To generate a header file, use the following command:</p> |
||
| 1676 | |||
| 1677 | <blockquote><pre> |
||
| 1678 | <b>mktclapp -header >appinit.h</b> |
||
| 1679 | </pre></blockquote> |
||
| 1680 | |||
| 1681 | <p>If you want to generate an application initialization file |
||
| 1682 | for <b>hello.tcl</b>, then do this:</p> |
||
| 1683 | |||
| 1684 | <blockquote><pre> |
||
| 1685 | <b>mktclapp hello.tcl -main-script hello.tcl >appinit.c</b> |
||
| 1686 | </pre></blockquote> |
||
| 1687 | |||
| 1688 | <p>Everything is controlled by command-line options. But it |
||
| 1689 | doesn't take a large project for the number of command-line |
||
| 1690 | options to become excessive. So mktclapp allows you to specify |
||
| 1691 | the name of a file which is read to extract additional |
||
| 1692 | command-line options. In fact, the <b>.mta</b> configuration |
||
| 1693 | files that xmktclapp.tcl generates are just such files.</p> |
||
| 1694 | |||
| 1695 | <p>Suppose, for example, that you use xmktclapp.tcl to generate |
||
| 1696 | a configuration file named <b>hello.mta</b>. Then to use |
||
| 1697 | this configuration file to generate an application initialization |
||
| 1698 | file, you just type:</p> |
||
| 1699 | |||
| 1700 | <blockquote><pre> |
||
| 1701 | <b>mktclapp -f hello.mta >hello.c</b> |
||
| 1702 | </pre></blockquote> |
||
| 1703 | |||
| 1704 | <p>In fact, this is all xmktclapp.tcl does when you press the |
||
| 1705 | "Build" button. (Grep for "exec mktclapp" on the xmktclapp.tcl |
||
| 1706 | source code and you will see.) |
||
| 1707 | If you look at the content of a configuration file, you will see |
||
| 1708 | that it consists of comments and command-line options for |
||
| 1709 | mktclapp. Go ahead. Look at an <b>.mta</b> file now. The |
||
| 1710 | contents are instructive.</p> |
||
| 1711 | |||
| 1712 | <p>So one easy way to add mktclapp to a Makefile is to generate |
||
| 1713 | the configuration file (the <b>.mta</b> file) using xmktclapp.tcl, |
||
| 1714 | then add a rule like this to your Makefile:</p> |
||
| 1715 | |||
| 1716 | <blockquote><pre> |
||
| 1717 | <b>hello.c: hello.mta |
||
| 1718 | mktclapp -f hello.mta >hello.c</b> |
||
| 1719 | </pre></blockquote> |
||
| 1720 | |||
| 1721 | <p>That's all I'm going to say about running mktclapp from the |
||
| 1722 | command line. |
||
| 1723 | If you want to know more about the command-line options available |
||
| 1724 | with mktclapp and how they work, you should look at the output |
||
| 1725 | of</p> |
||
| 1726 | |||
| 1727 | <blockquote><pre> |
||
| 1728 | <b>mktclapp -help</b> |
||
| 1729 | </pre></blockquote> |
||
| 1730 | |||
| 1731 | <p>and study some of the configuration files that xmktclapp generates. |
||
| 1732 | It isn't difficult and you should have no trouble figuring it |
||
| 1733 | out given the above hints.</p> |
||
| 1734 | |||
| 1735 | <a name="toc18b"><!-- AUTO --> |
||
| 1736 | <h2 align=center> |
||
| 1737 | Using MkTclApp With The MingW32 Compiler For Windows |
||
| 1738 | </h2> |
||
| 1739 | |||
| 1740 | <!-- <p><i>This section was added on October 8, 1999</i></p> --> |
||
| 1741 | |||
| 1742 | <p>By default, the cygwin compiler generates an executable that |
||
| 1743 | requires a special DLL named <b>cygwin1.dll</b>. This DLL is |
||
| 1744 | covered by the GNU Public License. Consequently, you cannot |
||
| 1745 | distribute the DLL with your product unless you are also willing |
||
| 1746 | to distribute your source code. Many managers find this |
||
| 1747 | restruction unacceptable.</p> |
||
| 1748 | |||
| 1749 | <p>If you don't want to use the cygwin1.dll library, you can still |
||
| 1750 | use the cygwin compiler. You simply have to give the compiler a |
||
| 1751 | special command-line option: <b>-mno-cygwin</b>. With the -mno-cygwin |
||
| 1752 | command-line option, the cygwin compiler will generate an executable |
||
| 1753 | that uses only native Windows DLLs. You are free to distribute such |
||
| 1754 | an executable without having to make the source code available.</p> |
||
| 1755 | |||
| 1756 | <p>The only problem with this approach is that the Tcl/Tk libraries |
||
| 1757 | that come with cygwin depend on the cygwin1.dll DLL. So if you use |
||
| 1758 | the -mno-cygwin switch, you won't be able to use the Tcl/Tk libraries |
||
| 1759 | that come in the cygwin package. You'll have to either compile the |
||
| 1760 | Tcl/Tk libraries yourself (using VC++) or get a copy from Scriptics.</p> |
||
| 1761 | |||
| 1762 | <p>Here is how you can use the Tcl/Tk DLLs and libraries from the standard |
||
| 1763 | Scriptics distributions with the cygwin compiler. First get and install |
||
| 1764 | the binary distribution of Tcl/Tk from Scriptics. The binary distribution |
||
| 1765 | contains the DLLs you'll need along with C header files and |
||
| 1766 | interface libraries. The DLLs and header files you can use as is. |
||
| 1767 | However, the libraries (tcl82.lib and tk82.lib) will only work with |
||
| 1768 | VC++. You'll need to create new libraries named tcl82.a and tk82.a |
||
| 1769 | for use with cygwin. I'll describe how to do this using the Tcl |
||
| 1770 | library as an example.</p> |
||
| 1771 | |||
| 1772 | <p>The first step is to generate a suitable DEF file. |
||
| 1773 | Execute the following commands from a Cygwin shell:</p> |
||
| 1774 | |||
| 1775 | <blockquote><pre> |
||
| 1776 | <b>echo EXPORTS >tcl82.def |
||
| 1777 | nm tcl82.lib | grep 'T _' | sed 's/.* T _//' >>tcl82.def |
||
| 1778 | </b></pre></blockquote> |
||
| 1779 | |||
| 1780 | <p>If you do it right, the DEF file will begin with the |
||
| 1781 | keyword "EXPORTS" then contain the name of every API function |
||
| 1782 | in the TCL library, one function name per line. Use the |
||
| 1783 | DEF file to generate the library <b>libtcl82.a</b> as follows:</p> |
||
| 1784 | |||
| 1785 | <blockquote><pre> |
||
| 1786 | <b>dlltool --def tcl82.def --dllname tcl82.dll --output-lib libtcl82.a |
||
| 1787 | </b></pre></blockquote> |
||
| 1788 | |||
| 1789 | <p>Follow the same steps to generate libtk82.a, then link your |
||
| 1790 | program against the new libtcl82.a and libtk82.a library files. |
||
| 1791 | Put the tcl82.dll and tk82.dll DLLs from the standard distribution |
||
| 1792 | in the same directory as your executable and everything should |
||
| 1793 | work.</p> |
||
| 1794 | |||
| 1795 | <a name="toc19"><!-- AUTO --> |
||
| 1796 | <h2 align=center> |
||
| 1797 | History Of Mktclapp And Summary |
||
| 1798 | </h2> |
||
| 1799 | |||
| 1800 | <p>I first started programming Tcl/Tk back in 1994, with Tk3.6. |
||
| 1801 | Right away, I needed a simple way to mix C/C++ with Tcl/Tk so |
||
| 1802 | I wrote the "Embedded Tk" or "ET" package. ET was and continues |
||
| 1803 | to be widely used even if its interface is a bit clunky.</p> |
||
| 1804 | |||
| 1805 | <p>Mktclapp was written as a follow-on to ET. It has the same |
||
| 1806 | goal as ET, to make it easier to program with a mixture of C/C++ |
||
| 1807 | and Tcl/Tk, but the interface is very different. I think |
||
| 1808 | the interface is much cleaner and easier to use. It is |
||
| 1809 | certainly much easier to maintain. I encourage all ET |
||
| 1810 | users to transition to using mktclapp as soon as possible.</p> |
||
| 1811 | |||
| 1812 | <p>The development of mktclapp began in the early fall of 1998. |
||
| 1813 | I have personally used mktclapp to develop applications for |
||
| 1814 | three separate clients. And other users have had success with |
||
| 1815 | mktclapp too, to judge from my e-mail and from the number |
||
| 1816 | of downloads.</p> |
||
| 1817 | |||
| 1818 | <p>I hope you find mktclapp useful in your own endeavors. |
||
| 1819 | If you do, I would appreciate a brief |
||
| 1820 | <a href="mailto:drh@acm.org">e-mail</a> telling me |
||
| 1821 | how you are using mktclapp and how it has helped you. |
||
| 1822 | Better still, if you find a bug or a missing feature, |
||
| 1823 | please let me know. Mktclapp has already been much improved |
||
| 1824 | by user feedback.</p> |
||
| 1825 | |||
| 1826 | <p>Please note that the mktclapp program itself, and the |
||
| 1827 | xmktclapp.tcl GUI, are covered under the |
||
| 1828 | <a href="http://www.gnu.ai.mit.edu/copyleft/gpl.html">GNU Public License</a>. |
||
| 1829 | But the C code that mktclapp generates (the part you link with your |
||
| 1830 | program) is free of any copyright. You can use it however you |
||
| 1831 | wish and you do not have to give away the source.</p> |
||
| 1832 | |||
| 1833 | <a name="toc20"><!-- AUTO --> |
||
| 1834 | <h2 align=center> |
||
| 1835 | Bibliography |
||
| 1836 | </h2> |
||
| 1837 | |||
| 1838 | <dl compact> |
||
| 1839 | <p><dt>[1]</dt> |
||
| 1840 | <dd> The Mktclapp Homepage. |
||
| 1841 | <a href="http://www.hwaci.com/sw/mktclapp/"> |
||
| 1842 | http://www.hwaci.com/sw/mktclapp/ |
||
| 1843 | </a> |
||
| 1844 | </dd></p> |
||
| 1845 | <p><dt>[2]</dt> |
||
| 1846 | <dd> The Embedded Tk Homepage. |
||
| 1847 | <a href="http://www.hwaci.com/sw/et/"> |
||
| 1848 | http://www.hwaci.com/sw/et/ |
||
| 1849 | </a> |
||
| 1850 | </dd></p> |
||
| 1851 | <p><dt>[3]</dt> |
||
| 1852 | <dd> The Tcl Consortium Homepage |
||
| 1853 | <a href="http://www.tclconsortium.org/"> |
||
| 1854 | http://www.tclconsortium.org/ |
||
| 1855 | </a> |
||
| 1856 | </dd></p> |
||
| 1857 | <p><dt>[4]</dt> |
||
| 1858 | <dd> The homepage for Scriptics Corporations |
||
| 1859 | <a href="http://www.scriptics.com/"> |
||
| 1860 | http://www.scriptics.com/ |
||
| 1861 | </a> |
||
| 1862 | </dd></p> |
||
| 1863 | <p><dt>[5]</dt> |
||
| 1864 | <dd> The Cygwin Compiler Page at Cygnus. |
||
| 1865 | <a href="http://sourceware.cygnus.com/cygwin/"> |
||
| 1866 | http://sourceware.cygnus.com/cygwin/ |
||
| 1867 | </a> |
||
| 1868 | </dd></p> |
||
| 1869 | <p><dt>[6]</dt> |
||
| 1870 | <dd> Dennis LaBelle's Freewrap Program. |
||
| 1871 | <a href="http://www.albany.net/~dlabelle/freewrap/freewrap.html"> |
||
| 1872 | http://www.albany.net/~dlabelle/freewrap/freewrap.html |
||
| 1873 | </a> |
||
| 1874 | </dd></p> |
||
| 1875 | <p><dt>[7]</dt> |
||
| 1876 | <dd> Mumit Khan's Tcl/Tk Archives for the Cygwin and Mingw32 Compilers. |
||
| 1877 | <a href="http://www.xraylith.wisc.edu/~khan/software/tcl"> |
||
| 1878 | http://www.xraylith.wisc.edu/~khan/software/tcl |
||
| 1879 | </a> |
||
| 1880 | </dd></p> |
||
| 1881 | <p><dt>[8]</dt> |
||
| 1882 | <dd> Daniel Roche's balloon widget for Tcl/Tk |
||
| 1883 | <a href="http://www.multimania.com/droche/tkballoon/index.html"> |
||
| 1884 | http://www.multimania.com/droche/tkballoon/index.html |
||
| 1885 | </a> |
||
| 1886 | </dd></p> |
||
| 1887 | <p><dt>[9]</dt> |
||
| 1888 | <dd> Cameron Laird's Personal Notes On Tcl Compilers |
||
| 1889 | <a href="http://starbase.neosoft.com/~claird/comp.lang.tcl/tcl_compilers.html"> |
||
| 1890 | http://starbase.neosoft.com/~claird/comp.lang.tcl/tcl_compilers.html</a> |
||
| 1891 | </dd></p> |
||
| 1892 | <p><dt>[10]</dt> |
||
| 1893 | <dd> The BLT Extension |
||
| 1894 | <a href="http://www.tcltk.com/blt/"> |
||
| 1895 | http://www.tcltk.com/blt/ |
||
| 1896 | </a> |
||
| 1897 | </dd></p> |
||
| 1898 | <p><dt>[11]</dt> |
||
| 1899 | <dd> The GNU Public License |
||
| 1900 | <a href="http://www.gnu.ai.mit.edu/copyleft/gpl.html"> |
||
| 1901 | http://www.gnu.ai.mit.edu/copyleft/gpl.html |
||
| 1902 | </a> |
||
| 1903 | </dd></p> |
||
| 1904 | <p><dt>[12]</dt> |
||
| 1905 | <dd> Jan Nijtmans' Wrap Program |
||
| 1906 | <a href="http://home.wxs.nl/~nijtmans/wrap.html"> |
||
| 1907 | http://www.wxs.nl/~nijtmans/wrap.html |
||
| 1908 | </a> |
||
| 1909 | </dd></p> |
||
| 1910 | </dl> |
||
| 1911 | |||
| 1912 | <p><hr></p> |
||
| 1913 | <p align=right> |
||
| 1914 | D. Richard Hipp<br> |
||
| 1915 | <a href="mailto:drh@acm.org">drh@acm.org</a><br> |
||
| 1916 | Charlotte, NC<br> |
||
| 1917 | May 31, 1999 |
||
| 1918 | </p> |
||
| 1919 | |||
| 1920 | </body> |
||
| 1921 | </html> |