Commit | Line | Data |
0198fd3c |
1 | <html> |
2 | <head><title>Integrating FastCGI with Tcl</title> |
3 | </head> |
4 | |
5 | <body bgcolor="#FFFFFF" text="#000000" link="#cc0000" alink="#000011" |
6 | vlink="#555555"> |
7 | |
8 | <center> |
9 | <a href="/fastcgi/words"> |
10 | <img border=0 src="../images/fcgi-hd.gif" alt="[[FastCGI]]"></a> |
11 | </center> |
12 | <br clear=all> |
13 | <h3><center>Integrating FastCGI with Tcl</center></h3> |
14 | |
15 | <!--Copyright (c) 1996 Open Market, Inc. --> |
16 | <!--See the file "LICENSE.TERMS" for information on usage and redistribution--> |
17 | <!--of this file, and for a DISCLAIMER OF ALL WARRANTIES. --> |
18 | |
19 | <P ALIGN=CENTER> |
20 | Michael S. Shanzer |
21 | <BR> |
22 | Open Market, Inc. |
23 | <BR> |
24 | <EM>19 January 1995</EM> |
25 | </P> |
26 | |
27 | <h5 align=center> |
28 | Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, |
29 | MA 02142 U.S.A.<br> |
30 | Tel: 617-621-9500 Fax: 617-621-1703 URL: |
31 | <a href="http://www.openmarket.com/">http://www.openmarket.com/</a><br> |
32 | $Id: fcgi-tcl.htm,v 1.1 1997/09/16 15:36:26 stanleyg Exp $ <br> |
33 | </h5> |
34 | <hr> |
35 | |
36 | |
37 | <h3><a NAME = "S1">1. Introduction</a></h3> |
38 | |
39 | |
40 | Tcl (tool command language) is an embeddable scripting language |
41 | that's often used for CGI programming. Tcl is freely available |
42 | as a source kit.<p> |
43 | |
44 | We've built a Tcl interpreter that runs as a FastCGI application. Our |
45 | purpose in doing so was twofold: |
46 | |
47 | <ul> |
48 | <li><i>Create a useful artifact.</i> |
49 | Open Market has written many CGI applications using Tcl. |
50 | Now we'd like to turn them into FastCGI applications.<p> |
51 | <li><i>Demonstrate how easy it is to integrate FastCGI with an |
52 | existing program.</i> |
53 | The Tcl interpreter is a substantial program, so integrating |
54 | FastCGI with the Tcl interpreter is a good test of the |
55 | <tt>fcgi_stdio</tt> compatability library. |
56 | </ul> |
57 | |
58 | We've succeeded on both counts. We now have a platform for |
59 | migrating our Tcl-based CGI applications to FastCGI. And |
60 | the integration required a very small effort. The only source |
61 | code change to the Tcl interpreter was the routine addition of a |
62 | handful of new commands: <tt>FCGI_Accept</tt>, <tt>FCGI_Finish</tt>, |
63 | <tt>FCGI_SetExitStatus</tt>, and <tt>FCGI_StartFilterData</tt>.<p> |
64 | |
65 | The FastCGI-integrated Tcl interpreter works as usual when run |
66 | from a shell or as a CGI program. You don't need two Tcls, |
67 | one for FastCGI and one for other uses.<p> |
68 | |
69 | The remainder of this document gives a recipe you can follow to |
70 | build FastCGI into Tcl, explains what's happening in the recipe, |
71 | and illustrates the use of FastCGI Tcl with |
72 | an example program.<p> |
73 | |
74 | <h3><a NAME = "S2">2. Recipe</a></h3> |
75 | |
76 | Here are the assumptions embedded in the following recipe: |
77 | <ul> |
78 | <li>You are building Tcl 7.4p3, the current stable Tcl release |
79 | as this is written. |
80 | You unpack the Tcl kit into a directory <tt>tcl7.4</tt> |
81 | that's a sibling of the FastCGI kit directory |
82 | <tt>fcgi-devel-kit</tt>.<p> |
83 | |
84 | <li>You have gcc version 2.7 |
85 | installed on your system, and use it in the build. |
86 | gcc is convenient because it supports the <tt>-include</tt> |
87 | command-line option |
88 | that instructs the C preprocessor to include a specific file before |
89 | processing any other include files. This allows you to include |
90 | <tt>fcgi_stdio.h</tt> without modifying Tcl source files. (The |
91 | reason for specifying gcc version 2.7 is that I have |
92 | experienced bad behavior with an earlier version and the <tt>-include</tt> |
93 | flag -- the C preprocessor died with SIGABRT.)<p> |
94 | |
95 | <li>You have GNU autoconf |
96 | installed on your system. If you don't have GNU autoconf, |
97 | you will have to make certain edits by hand and |
98 | repeat these edits for each build platform.<p> |
99 | </ul> |
100 | |
101 | If those are valid assumptions, follow these steps: |
102 | <ol> |
103 | <li><i>Build the FastCGI Developer's Kit.</i> |
104 | Tcl needs to link against <tt>libfcgi.a</tt>, so |
105 | <a href="http://www.fastcgi.com/kit/doc/fcgi-devel-kit.htm#S2">build |
106 | the FastCGI Developer's Kit</a> |
107 | in order to create this library for your platform.<p> |
108 | |
109 | <li><i>Pull the Tcl 7.4p3 kit.</i> |
110 | You'll need the files |
111 | <a href="ftp://ftp.smli.com/pub/tcl/tcl7.4.tar.Z">tcl7.4.tar.Z</a>, |
112 | <a href="ftp://ftp.smli.com/pub/tcl/tcl7.4p1.patch.gz">tcl7.4p1.patch.gz</a>, |
113 | <a href="ftp://ftp.smli.com/pub/tcl/tcl7.4p2.patch.gz">tcl7.4p2.patch.gz</a>, |
114 | and |
115 | <a href="ftp://ftp.smli.com/pub/tcl/tcl7.4p3.patch.gz">tcl7.4p3.patch.gz</a>. |
116 | (Some older Netscape browsers can't perform these |
117 | retrievals because of a protocol conflict between Netscape |
118 | and Sun's firewall.)<p> |
119 | |
120 | Unpack the tar file in the parent directory of the |
121 | FastCGI kit directory you used in the previous step, |
122 | so that the directories <tt>tcl7.4</tt> and <tt>fcgi-devel-kit</tt> |
123 | are siblings. After unpacking the tar file, follow the directions |
124 | in the <tt>README</tt> to apply the patches.<p> |
125 | |
126 | The <a href="http://www.sunlabs.com:80/research/tcl/">Sun Labs Tcl/Tk |
127 | Project Page</a> contains a wealth of information on Tcl, including |
128 | up to date information on the latest kits.<p> |
129 | |
130 | <li><i>Copy the files <tt>tclFCGI.c</tt>, <tt>tclAppInit.c</tt>, |
131 | <tt>Makefile.in</tt>, and <tt>configure.in</tt> from the FastCGI kit.</i> |
132 | <pre> |
133 | > cd tcl7.4 |
134 | > mv tclAppInit.c tclAppInit.c.orig |
135 | > mv Makefile.in.orig Makefile.in.orig.orig |
136 | > mv Makefile.in Makefile.in.orig |
137 | > mv configure.in configure.in.orig |
138 | > cp ../fcgi-devel-kit/tcl/tcl7.4/* . |
139 | > cp ../fcgi-devel-kit/tcl/common/* .</pre> |
140 | |
141 | <li><i>Create a new <tt>configure</tt> script.</i> |
142 | <pre> |
143 | > autoconf</pre> |
144 | |
145 | <li><i>Configure and build.</i> |
146 | <pre> |
147 | > ./configure |
148 | > make</pre> |
149 | The <tt>make</tt> creates the Tcl interpreter <tt>tclsh</tt> |
150 | and library archive <tt>libtcl.a</tt> (for embedding Tcl in |
151 | your own C applications). The Tcl <tt>README</tt> file |
152 | explains how you can experiment with <tt>tclsh</tt> |
153 | without installing it in a standard place.<p> |
154 | </ol> |
155 | |
156 | <h3><a NAME = "S3">3. Recipe Explained</a></h3> |
157 | |
158 | The recipe alone is fine if you are using Tcl 7.4p3, you have gcc |
159 | version 2.7, and you have GNU autoconf. In case one or more of these |
160 | assumptions doesn't hold for you, and to illuminate how little work was |
161 | involved in integrating FastCGI, here's an explanation of how |
162 | and why you would modify the files <tt>tclAppInit.c</tt>, |
163 | <tt>Makefile.in</tt>, and <tt>configure.in</tt> from the Tcl kit. |
164 | |
165 | <ul> |
166 | <li><tt>tclAppInit.c</tt>:<p> |
167 | <ul> |
168 | <li>Add the following three lines of code |
169 | to the function <tt>Tcl_AppInit</tt> after the call |
170 | to <tt>Tcl_Init</tt> and after the comment about calling init |
171 | procedures: |
172 | <pre> |
173 | if (FCGI_Init(interp) == TCL_ERROR) { |
174 | return TCL_ERROR; |
175 | }</pre> |
176 | This registers four Tcl commands (<tt>FCGI_Accept</tt>, |
177 | <tt>FCGI_Finish</tt>, <tt>FCGI_SetExitStatus</tt>, and |
178 | <tt>FCGI_StartFilterData</tt>), implemented in |
179 | <tt>tclFCGI.c</tt>, with the Tcl interpreter.<p> |
180 | </ul> |
181 | |
182 | <li><tt>Makefile.in</tt>:<p> |
183 | <ul> |
184 | <li>Add <tt>tclFCGI.o</tt> to the <tt>GENERIC_OBJS</tt> variable, and |
185 | add <tt>tclFCGI.c</tt> to the <tt>SRCS</tt> variable.<p> |
186 | |
187 | This builds the FastCGI Tcl commands and |
188 | links them into the Tcl interpreter.<p> |
189 | |
190 | <li>Add <tt>-I../fcgi-devel-kit/include |
191 | -include ../fcgi-devel-kit/include/fcgi_stdio.h</tt> |
192 | to the <tt>CFLAGS</tt> variable.<p> |
193 | |
194 | This includes <tt>fcgi_stdio.h</tt> |
195 | when compiling C code for the Tcl interpreter, overriding |
196 | the normal <tt>stdio</tt> types, variables, and functions.<p> |
197 | |
198 | <li>Add <tt>../fcgi-devel-kit/libfcgi/libfcgi.a</tt> before the |
199 | <tt>@LIBS@</tt> part of the <tt>LIBS</tt> variable.<p> |
200 | |
201 | This links the implementation of <tt>fcgi_stdio.h</tt> |
202 | into the Tcl interpreter, for use by the <tt>FCGI_accept</tt> |
203 | command and any code that uses <tt>stdio</tt> variables |
204 | or calls <tt>stdio</tt> functions.<p> |
205 | </ul><p> |
206 | |
207 | The last two edits will vary if you use a compiler other than gcc or |
208 | install the <tt>tcl7.4</tt> directory |
209 | somewhere else in relation to the <tt>fcgi-devel-kit</tt> directory.<p> |
210 | |
211 | <li><tt>configure.in</tt>:<p> |
212 | <ul> |
213 | <li> |
214 | Replace the lines |
215 | <pre> |
216 | AC_C_CROSS |
217 | CC=${CC-cc}</pre> |
218 | with the lines |
219 | <pre> |
220 | AC_PROG_CC |
221 | AC_C_CROSS</pre> |
222 | This selects gcc in preference to other C compilers.<p> |
223 | |
224 | <li> |
225 | Add the following lines just after the |
226 | <tt>AC_SUBST(CC)</tt> line: |
227 | <pre> |
228 | AC_CHECK_LIB(socket, main, [LIBS="$LIBS -lsocket"]) |
229 | AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"]) |
230 | AC_SUBST(LIBS)</pre> |
231 | This ensures that the socket libraries used by FastCGI |
232 | are linked into the Tcl interpreter.<p> |
233 | </ul> |
234 | If GNU autoconf is not available to you, you'll leave |
235 | <tt>configure.in</tt> alone and perform the following steps:<p> |
236 | <ul> |
237 | <li> |
238 | Execute |
239 | <pre> |
240 | > SETENV CC gcc</pre> |
241 | before running <tt>configure</tt>.<p> |
242 | |
243 | <li> |
244 | If you are running on a SVR4-derived Unix platform, |
245 | edit <tt>Makefile</tt> to add |
246 | <tt>-lsocket -lnsl</tt> to the <tt>LIBS</tt> value |
247 | after running <tt>configure</tt>.<p> |
248 | </ul> |
249 | If you ever re-run <tt>configure</tt>, you'll need to repeat |
250 | these steps.<p> |
251 | |
252 | </ul> |
253 | |
254 | |
255 | <h3><a NAME = "S4">4. Writing FastCGI applications in Tcl</a></h3> |
256 | |
257 | The Tcl program <tt>tcl/tiny-tcl-fcgi</tt> performs the same |
258 | function as the C program <tt>examples/tiny-fcgi.c</tt> |
259 | that's used as an example in the |
260 | <a href="fcgi-devel-kit.html#S3.1.1">FastCGI Developer's Kit |
261 | document</a>. Here's what the Tcl version looks like:<p> |
262 | |
263 | <pre> |
264 | #!./tclsh |
265 | set count 0 |
266 | while {[FCGI_Accept] >= 0 } { |
267 | incr count |
268 | puts -nonewline "Content-type: text/html\r\n\r\n" |
269 | puts "<title>FastCGI Hello! (Tcl)</title>" |
270 | puts "<h1>FastCGI Hello! (Tcl)</h1>" |
271 | puts "Request number $count running on host <i>$env(SERVER_NAME)</i>" |
272 | } |
273 | </pre> |
274 | |
275 | If you've built Tcl according to the recipe and you have a Web server |
276 | set up to run FastCGI applications, load the FastCGI Developer's Kit |
277 | Index Page in that server and run this Tcl application now.<p> |
278 | |
279 | The script invokes Tcl indirectly via the symbolic link |
280 | <tt>examples/tclsh</tt>. It does this because HP-UX has a limit of 32 |
281 | characters for the first line of a command-interpreter file such as |
282 | <tt>examples/tiny-tcl-fcgi</tt>. If you run on HP-UX you won't want |
283 | to sprinkle symbolic links to <tt>tclsh</tt> everywhere, so you should install |
284 | <tt>tclsh</tt> with a shorter pathname than |
285 | <tt>/usr/local/tcl7.4-fcgi/bin/tclsh7.4</tt>.<p> |
286 | |
287 | The Tcl command <tt>FCGI_Accept</tt> treats the initial |
288 | environment differently than the C function <tt>FCGI_Accept</tt>. The |
289 | first call to the |
290 | C function <tt>FCGI_Accept</tt> replaces the initial environment with |
291 | the environment of the first request. The first call to the Tcl command |
292 | <tt>FCGI_Accept</tt> adds the variable bindings of the first request |
293 | to the bindings present in the initial environment. So when the first |
294 | call to <tt>FCGI_Accept</tt> returns, bindings from the initial |
295 | environment are still there (unless, due to naming conflicts, some of |
296 | them have been overwritten by the first request). The next call to |
297 | <tt>FCGI_Accept</tt> removes the bindings made on the previous call |
298 | before adding a new set for the request just accepted, again preserving |
299 | the initial environment.<p> |
300 | |
301 | The FastCGI-integrated <tt>tclsh</tt> also includes |
302 | commands <tt>FCGI_Finish</tt>, <tt>FCGI_SetExitStatus</tt>, |
303 | and <tt>FCGI_StartFilterData</tt> that correspond to |
304 | C functions in <tt>fcgi_stdio.h</tt>; see the manpages for |
305 | full information.<p> |
306 | |
307 | Converting a Tcl CGI application to FastCGI is not fundamentally |
308 | different from converting a C CGI application. You separate |
309 | the portion of the application that performs one-time |
310 | initialization from the portion that performs per-request |
311 | processing. You put the per-request processing into a loop |
312 | controlled by <tt>FCGI_Accept</tt>.<p> |
313 | |
314 | <HR> |
315 | <ADDRESS><A HREF="mailto:shanzer@openmarket.com">Mike Shanzer // shanzer@openmarket.com</A></ADDRESS> |
316 | </body> |
317 | </html> |