Updated 2012-12-31 05:49:42 by RLE

There are three routes to linking Fortran code into Tcl. One is simply drive you Fortran application using expect. Secondly we might be able to import the Tcl C API into a format useful for Fortran and link Tcl into the Fortran module.

This section deals with wrapping the Fortran code into a Tcl package.

The GNU Compiler Collection is useful here as the Fortran component (g77) generates objects that are directly compatible with the C generated objects. Other Fortran compilers may also work. YMMV.

Two files are given below, power.f is Fortran77 code that provides a single function. tclpower.c is the C wrapper code that creates an interface callable from Tcl. To compile this using gcc/g77 on unix or the Mingw tools under Windows you should do:
  g77 -c power.f
  gcc -I/opt/tcl/include -DBUILD_power -DUSE_TCL_STUBS -c tclpower.c
  gcc -shared tclpower.o power.o /opt/tcl/lib/tclstub84.lib -o power01.dll

(fix the extensions for your system. Extending the TEA build system is simple enough, but I don't want to clutter the page here.)

Now you can use the library:
  % load power01.dll Power
  % power 5.5
  11803.0648209

AM I am working on a Fortran version for Critcl - the pieces are coming together! With this package, extending Tcl with Fortran will become much easier - see Critcl goes Fortran

AM (9 november 2007) What about extending a Fortran program, say, with a Fortran-like scripting language? See: Almost Fortran

power.f
 c     power.f - Copyright (C) 2003 Pat Thoyts <[email protected]>
 c
 c     Demonstrate linking Fortran subroutines into Tcl packages.
 c
 c     $Id: 8507,v 1.5 2007-03-10 07:00:14 jcw Exp $
 c
       double precision function power(x)
       double precision x

       power = x ** x

       end function power

tclpower.c
 /* tclpower.c - Copyright (C) 2003 Pat Thoyts <[email protected]>
  *
  * Demonstrate creation of a Tcl module that interfaces to Fortran
  * subroutines.
  *
  * This package relies upon g77's ability to create objects that can be
  * easily linked into C generated modules.
  *
  * $Id: 8507,v 1.5 2007-03-10 07:00:14 jcw Exp $
  */

 #include <tcl.h>

 #ifdef BUILD_power
 #undef TCL_STORAGE_CLASS
 #define TCL_STORAGE_CLASS DLLEXPORT
 #endif

 #define PACKAGE "Power"
 #ifndef VERSION
 #define VERSION "0.1"
 #endif

 EXTERN int Power_Init(Tcl_Interp *interp);
 EXTERN int Power_SafeInit(Tcl_Interp *interp);

 /*
  * Declare the fortran functions - to be linked in to this executable.
  */
 double power_(CONST double *d);

 /*
  * Tcl command procedures
  */
 static Power_ObjCmd(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);

 /* ---------------------------------------------------------------------- */

 int
 Power_Init(Tcl_Interp* interp)
 {
 #ifdef USE_TCL_STUBS
     Tcl_InitStubs(interp, "8.1", 0);
 #endif

     // Call Tcl_CreateObjCommand etc.
     Tcl_CreateObjCommand(interp, "power", Power_ObjCmd, (ClientData *)NULL,
                          (Tcl_CmdDeleteProc *)NULL);

     return Tcl_PkgProvide(interp, PACKAGE, VERSION);
 }

 int
 Test2_SafeInit(Tcl_Interp* interp)
 {
     // We don't need to be specially safe so...
     return Power_Init(interp);
 }

 /* ---------------------------------------------------------------------- */

 static int
 Power_ObjCmd(ClientData clientData, Tcl_Interp *interp,
               int objc, Tcl_Obj *CONST objv[])
 {
     double d, dr;
     int r = TCL_OK;

     if (objc != 2) {
         Tcl_WrongNumArgs(interp, 1, objv, "real value");
         r = TCL_ERROR;
     }

     if (r == TCL_OK)
         r = Tcl_GetDoubleFromObj(interp, objv[1], &d);

     if (r == TCL_OK)
     {
         dr = power_(&d);
         Tcl_SetObjResult(interp, Tcl_NewDoubleObj(dr));
     }

     return r;
 }

 /* ---------------------------------------------------------------------- */
 /*
  * Local variables:
  *   mode: c
  *   indent-tabs-mode: nil
  * End:
  */