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