Ftcl: Creating extensions in Fortran

The default Fortran extension

If you write an extension to Tcl, you have to consider the way the load command works. It will load the shared or dynamic library and call a first routine with a name it can determine from the package. So:
   package require Ftcl
causes the following to happen: This routine has to be written in C, so if you do not want to do anything in C, you are stuck with the name "Ftcl".

The following Tcl commands are created by this default Ftcl package to transfer information directly to the Fortran routines:

ftn_exec ftn_proc ?args

This command starts a Fortran routine "ftn_exec" that you need to write yourself. The first argument, "ftn_proc" is the name of the Fortran service that should be executed. It may have any number of additional arguments.

The return value is in-line with the Tcl conventions:

ftn_config ?args

This command sets the configuration options. Currently, there are only the debugging and trace options:
ftn_config debug returns the current debug mode
ftn_config debug true turns debugging on, and
ftn_config debug false turns it off.
ftn_config trace returns the current trace mode
ftn_config trace true turns tracing mode on (that is, all calls are reported; implies debugging output as well, but this may be set independently)
ftn_config trace false turns tracing mode off (the debug state is not affected).
In debugging mode, accessing variables and executing services is reported, including if it was successful (especially accessing non-existent variables is reported explicitly). In tracing mode all calls to the Fortran-accessible routines are reported.

PM: customising the interface

Fortran services

The routine ftn_exec in the default extension is meant as a sort of gateway for specific routines. Here is a small and rather impractical example that uses the Fortran 90 library routine, random_number to return a random number.
     subroutine ftcl_exec( service, noargs, error )
     character(len=*), intent(in) :: service
     integer, intent(in)          :: noargs
     integer, intent(in)          :: ierror

     !
     ! Service: return a random number
     !
     if ( service == 'random' ) then
        call random( rnd )
        call ftcl_set_result( rnd )
     endif
     !
     ! Service: ...
     !
     if ( service == '...' ) then
        ...
     endif
     ...
     end

     subroutine random( rnd )
     implicit none
     real, intent(out) :: rnd

     call random_number( rnd )
     end

Technical details

The interface described in the previous sections assumes that you are using Fortran 90/95. By using the module FTCL (the source code is contained in the file ftcl_mod.f90) you have access to the generic names of the various routines, so that you do not have to worry about the type of the data.

If you are using a FORTRAN 77 compiler, then you will have to use the specific names.

The routine ftcl_get is the generic name of a set of related routines:

In a similar way, the put routines are implemented as a set of related routines, callable via the generic name ftcl_put. This way, there is no need to remember the specific names (or the details involved in accessing arrays).

The implementation does not hide an essential difference in the handling of arguments though:

It is not the intention of this documentation to explain either language in detail, but for the sake of understanding, let us take again the impractical example given above:

The service ftn_exec random is meant to return a random value using the Fortran 90 library routine, random_number.

     subroutine ftcl_exec( ... )
     ...
     !
     ! Service: return a random number
     !
     if ( service == 'random' ) then
        call random( rnd )
     endif
     !
     ! Service: ...
     !
     if ( service == '...' ) then
     ...
     return
     end

     subroutine random( rnd )
     use ftcl

     implicit none
     real, intent(out) :: rnd

     call random_number( rnd )
     return
     end

The problem is that the result should be passed back to Tcl, either as a result string or as a change to the first argument. The first can be achieved by setting the result:

     call ftcl_set_result( rnd )

The second can be achieved by assuming the first argument to be the name of a variable:

     call ftcl_get_arg( 1, varname )
     call ftcl_put( varname, rnd )