Add $Id$ string and beautify.
[catagits/fcgi2.git] / doc / fcgi-tcl.gut
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 &copy; 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] &gt;= 0 } {
259     incr count
260     puts -nonewline "Content-type: text/html\r\n\r\n"
261     puts "&lt;title&gt;FastCGI Hello! (Tcl)&lt;/title&gt;"
262     puts "&lt;h1&gt;FastCGI Hello! (Tcl)&lt;/h1&gt;"
263     puts "Request number $count running on host &lt;i&gt;$env(SERVER_NAME)&lt;/i&gt;"
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>