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: */