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