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