initial commit
[fcgi] / doc / fcgi-tcl.htm
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 &copy; 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&#39;s often used for CGI programming. Tcl
50          is freely available as a source kit.
51       </P>
52       <P>
53          We&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;t perform these retrievals because of a protocol conflict between Netscape and Sun&#39;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     &gt; cd tcl7.4
147     &gt; mv tclAppInit.c tclAppInit.c.orig
148     &gt; mv Makefile.in.orig Makefile.in.orig.orig
149     &gt; mv Makefile.in Makefile.in.orig
150     &gt; mv configure.in configure.in.orig
151     &gt; cp ../fcgi-devel-kit/tcl/tcl7.4/* .
152     &gt; 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     &gt; autoconf
159 </PRE>
160          </LI>
161          <LI>
162             <I>Configure and build.</I> 
163 <PRE>
164     &gt; ./configure
165     &gt; 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&#39;t hold for you, and to illuminate how little work was involved
179          in integrating FastCGI, here&#39;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=&quot;$LIBS -lsocket&quot;])
271 AC_CHECK_LIB(nsl, main, [LIBS=&quot;$LIBS -lnsl&quot;])
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&#39;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     &gt; 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&#39;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&#39;s used as an example in the <A HREF="fcgi-devel-kit.htm#S3.1.1">FastCGI
311          Developer&#39;s Kit document</A>. Here&#39;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] &gt;= 0 } {
319     incr count
320     puts -nonewline &quot;Content-type: text/html\r\n\r\n&quot;
321     puts &quot;&lt;title&gt;FastCGI Hello! (Tcl)&lt;/title&gt;&quot;
322     puts &quot;&lt;h1&gt;FastCGI Hello! (Tcl)&lt;/h1&gt;&quot;
323     puts &quot;Request number $count running on host &lt;i&gt;$env(SERVER_NAME)&lt;/i&gt;&quot;
324 }
325 </PRE>
326       <P>
327          If you&#39;ve built Tcl according to the recipe and you have a Web server set up to run FastCGI applications,
328          load the FastCGI Developer&#39;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&#39;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