f860fcc5a508d8192927759bc072dd0c2d44bc39
[catagits/fcgi2.git] / doc / fcgi-tcl.htm
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="http://fastcgi.com">
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 &copy; 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.2 2001/05/14 13:00:30 robs 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="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 function as the C 
258 program <tt>examples/tiny-fcgi.c</tt> that's used as an example in the <a href="fcgi-devel-kit.htm#S3.1.1">FastCGI 
259 Developer's Kit document</a>. Here's what the Tcl version looks like:
260 <p>
261
262 <pre>
263 #!./tclsh
264 set count 0 
265 while {[FCGI_Accept] &gt;= 0 } {
266     incr count
267     puts -nonewline "Content-type: text/html\r\n\r\n"
268     puts "&lt;title&gt;FastCGI Hello! (Tcl)&lt;/title&gt;"
269     puts "&lt;h1&gt;FastCGI Hello! (Tcl)&lt;/h1&gt;"
270     puts "Request number $count running on host &lt;i&gt;$env(SERVER_NAME)&lt;/i&gt;"
271 }
272 </pre>
273
274 If you've built Tcl according to the recipe and you have a Web server
275 set up to run FastCGI applications, load the FastCGI Developer's Kit
276 Index Page in that server and run this Tcl application now.<p>
277
278 The script invokes Tcl indirectly via the symbolic link
279 <tt>examples/tclsh</tt>.  It does this because HP-UX has a limit of 32
280 characters for the first line of a command-interpreter file such as
281 <tt>examples/tiny-tcl-fcgi</tt>.  If you run on HP-UX you won't want
282 to sprinkle symbolic links to <tt>tclsh</tt> everywhere, so you should install
283 <tt>tclsh</tt> with a shorter pathname than
284 <tt>/usr/local/tcl7.4-fcgi/bin/tclsh7.4</tt>.<p>
285
286 The Tcl command <tt>FCGI_Accept</tt> treats the initial
287 environment differently than the C function <tt>FCGI_Accept</tt>.  The
288 first call to the
289 C function <tt>FCGI_Accept</tt> replaces the initial environment with
290 the environment of the first request.  The first call to the Tcl command
291 <tt>FCGI_Accept</tt> adds the variable bindings of the first request
292 to the bindings present in the initial environment.  So when the first
293 call to <tt>FCGI_Accept</tt> returns, bindings from the initial
294 environment are still there (unless, due to naming conflicts, some of
295 them have been overwritten by the first request).  The next call to
296 <tt>FCGI_Accept</tt> removes the bindings made on the previous call
297 before adding a new set for the request just accepted, again preserving
298 the initial environment.<p>
299
300 The FastCGI-integrated <tt>tclsh</tt> also includes
301 commands <tt>FCGI_Finish</tt>, <tt>FCGI_SetExitStatus</tt>,
302 and <tt>FCGI_StartFilterData</tt> that correspond to
303 C functions in <tt>fcgi_stdio.h</tt>; see the manpages for
304 full information.<p>
305
306 Converting a Tcl CGI application to FastCGI is not fundamentally
307 different from converting a C CGI application.  You separate
308 the portion of the application that performs one-time
309 initialization from the portion that performs per-request
310 processing.  You put the per-request processing into a loop
311 controlled by <tt>FCGI_Accept</tt>.<p>
312
313 <HR>
314 <ADDRESS><A HREF="mailto:shanzer@openmarket.com">Mike Shanzer // shanzer@openmarket.com</A></ADDRESS>
315 </body>
316 </html>