Interfacing between Fortran and C - a little utility

  • Follow


Hello,

for many years I have been using all manner of methods to interface
between Fortran
and C and I welcome the facilities that Fortran 2003 offers. But until
the time that
Fortran compilers can be counted on to adhere to that standard (and in
particular
the C bindings part), here is a little program that I recently
concocted to solve
several problems:
- It automatically determines what naming convention is used (from the
set of
  conventions that I have come across over the years)
- It automatically determines if the hidden string length argument
appears after
  the string argument or not
- It tries to determine if - on Windows - the __stdcall calling
convention is used or not.
  This part is a bit shaky - it relies on the use of the MS Visual C/C+
+ compiler for
  the C code. I have not checked if this convention is also used with
gcc on Cygwin or
  MinGW. Still, the program can be easily adjusted if that is the
case.

It consists of a Fortran main program and a set of C routines - the
trick is that
each of these routines does the same thing but only one is called,
picked up by the
linker as a consequence of the Fortran naming convention :). I
developed it in the
context of my Ftcl project (http://ftcl.sourceforge.net), hence the
references to Tcl.

Maybe this will be helpful for others as well.

Regards,

Arjen

--- probe.f90 ---
! probe.f90 --
!     Try and identify the Fortran naming and calling convention
!     - part of Ftcl
!
!     Note:
!     This is the Fortran part of a program  that uses a few tricks
!     to determine:
!     - The naming convention for the Fortran compiler (including
!       the current options that influence this convention).
!       The result will be:
!       - One of FOR_ALL_LOWER, FOR_ALL_CAPS, FOR_UNDERSCORE or
FOR_DBL_UNDERSCORE
!         will be defined. These are the most common naming
conventions
!     - The macro IN_BETWEEN is defined or undefined so that string
!       arguments can be properly passed
!     - The macro FOR_CALL is defined to capture the correct calling
!       convention vis-a-vis stack clean-up
!     - The values of these macros are stored in a file
"ftcl_conventions.h"
!
!     If the program fails, it will need to be expanded, as that is an
!     indication that this particular combination of Fortran and C
!     compilers is not yet supported.
!
program probe

    character(len=7) :: first  = 'Fortran'
    character(len=3) :: second = 'Tcl'

    call probe_c( first, second )

end program probe

--- probe_c.c ---
/* probe_c.c --
 *     Companion to the file probe.f90. Together they form a program
 *     that will write a header file with the right macros for
 *     setting up the interface between Fortran and C.
 *
 */

#include <stdio.h>
#include <stdlib.h>

/* probe_c --
       Plainly named version
*/

void probe_c( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_ALL_LOWER\n" ) ;
    fprintf( outfile, "#define FOR_CALL\n" ) ;

    /* If hidden length argument in between, then len_first must be 7
*/
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention -
assuming NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}

/* PROBE_C --
       All capitals version - possibly __stdcall too
*/
#ifdef _MSV_VER_
#define FOR_CALL __stdcall
#else
#define FOR_CALL
#endif

void FOR_CALL PROBE_C( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_ALL_CAPS\n" ) ;
#ifdef _MSC_VER_
    fprintf( outfile, "#define FOR_CALL __stdcall\n" ) ;
#else
    fprintf( outfile, "#define FOR_CALL\n" ) ;
#endif

    /* If hidden length argument in between, then len_first must be 7
*/
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention -
assuming NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}

/* probe_c_ --
       Single underscore
*/
void FOR_CALL probe_c_( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_UNDERSCORE\n" ) ;
    fprintf( outfile, "#define FOR_CALL\n" ) ;

    /* If hidden length argument in between, then len_first must be 7
*/
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention -
assuming NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}

/* probe_c__ --
       Double underscore (for Fortran names that have an embedded
underscore)
*/
void FOR_CALL probe_c__( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_DBL_UNDERSCORE\n" ) ;
    fprintf( outfile, "#define FOR_CALL\n" ) ;

    /* If hidden length argument in between, then len_first must be 7
*/
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention -
assuming NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}
0
Reply arjen.markus (2628) 5/29/2008 7:04:35 AM

hello  AM,
for many reason, i found i can make my program better by using c
subroutines...but my poor knowledge on C prevents me for doing that.
can u give a small example of that using this utility?
0
Reply bnrj.rudra (344) 5/30/2008 9:43:26 AM


On 30 mei, 11:43, rudra <bnrj.ru...@gmail.com> wrote:
> hello =A0AM,
> for many reason, i found i can make my program better by using c
> subroutines...but my poor knowledge on C prevents me for doing that.
> can u give a small example of that using this utility?

Well, what it does is simply determine the values of
several macros as explained in the comments. You will
have to use these macros for setting up the Fortran-C interface.

First:
Create the program with the Fortran and C compilers you want to use.
Second:
Run it to get the values for these macros in an include file.
Third:
A C function "my_func" like below could then be interfaced to:

#include "ftcl_conventions.h"

#ifdef FOR_UNDERSCORE
#define my_func my_func_
#endif

#ifdef FOR_DBL_UNDERSCORE
#define my_func my_func__
#endif

#ifdef FOR_ALL_CAPS
#define my_func MY_FUNC
#endif

/* So far, so good: the macro my_func will be
   replaced by the correct internal Fortran name
   Now: the two aspects of the calling convention
*/

void FOR_CALL my_func(
    char *string,
#ifdef IN_BETWEEN
    int len_string,
#endif
    int value
#ifndef IN_BETWEEN
   ,int len_string
#endif
) {
    ...
}

The macro FOR_CALL must have the value __stdcall on Windows
for some compilers, and the position of the hidden argument
that holds the length of a string argument can differ.

If you use this particular utility, you do not have to worry
about what the Fortran compiler produces yourself. The program
does this automatically for you.

Regards,

Arjen
0
Reply arjen.markus (2628) 5/30/2008 10:00:47 AM

2 Replies
42 Views

(page loaded in 0.112 seconds)

Similiar Articles:













7/14/2012 10:48:33 PM


Reply: