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