C <--> FORTRAN, but without ISO_C_BINDING

A

Arjan

Hi!

On sister forum Comp.Lang.Fortran I had a discussion about connecting
Proj-4 (a coordinate transformation library, written in C) to my
Fortran project. I do now have a working connection, but it requires
the use of a module named ISO_C_BINDING. This module, which is part of
the F2003 standard, is not supported by the F95 compiler that will
produce our operational executable. Since the people on the Fortran
forum really have done their utmost to help me from their side, I
thought that maybe now you, with your background in C, could give it
the last push it needs.

My C-skills are utterly poor. The last serious code I wrote in C was
only a few hundreds of lines for my MSc thesis in the late 1980s.

My question is: how can I use the Proj-4 library libproj.a from within
my Fortran code, without using module ISO_C_BINDING?

A working C example, named test1.c, is:

----------------------------------------------------------------------------------------------------
#include "proj_api.h"
int p;
main(int argc, char **argv) {
projPJ pj_HIRLAM6, pj_latlong;
double x, y;
if (!(pj_HIRLAM6 = pj_init_plus("+proj=ob_tran +o_proj=eqc
+o_lat_p=30.0 +a=57.29578 +lon_0=0")) )
exit(1);
if (!(pj_latlong = pj_init_plus("+proj=latlong +ellps=clrk66")) )
exit(1);
while (scanf("%lf %lf", &x, &y) == 2) {
x *= DEG_TO_RAD;
y *= DEG_TO_RAD;
p = pj_transform(pj_latlong, pj_HIRLAM6, 1, 0, &x, &y, NULL );
printf("%.2f\t%.2f\n", x, y);
}
exit(0);
}
----------------------------------------------------------------------------------------------------

It compiles with: gcc test1.c -lproj -o test1.exe.

The Fortran sample using ISO_C_BINDING uses a Module named libmyp.f90
for the interfacing between C-library and Fortran-program:

----------------------------------------------------------------------------------------------------
MODULE LibMyP
!
! Module for interfacing between Proj-4 library libproj.a
! and Fortran. So far only pj_init_plus and pj_transform are
supported.
! More routines can be added in a similar way.
! Sample use:
!
! g95 libmyp.f90 testproj.f90 -lproj -o testproj.exe
!
! Formulate your compile statement with care!
! FIRST the sources, THEN the library-path and library!!
!
USE ISO_C_BINDING
IMPLICIT NONE
PRIVATE
PUBLIC :: pj_init_plus, pj_transform
!
INTERFACE
FUNCTION pj_init_plus(name) BIND(C,NAME='pj_init_plus')
USE ISO_C_BINDING
IMPLICIT NONE
TYPE(C_PTR) :: pj_init_plus
CHARACTER(KIND=C_CHAR) :: name(*)
END FUNCTION pj_init_plus

FUNCTION pj_transform(src, dst, point_count, point_offset, &
& x, y, z) BIND(C,NAME='pj_transform')
USE ISO_C_BINDING
IMPLICIT NONE
TYPE(C_PTR), VALUE :: src, dst
INTEGER(C_LONG), VALUE :: point_count
INTEGER(C_INT), VALUE :: point_offset
INTEGER(C_INT) :: pj_transform
REAL(C_DOUBLE) :: x, y, z
END FUNCTION pj_transform
END INTERFACE
!
END MODULE LibMyP
----------------------------------------------------------------------------------------------------


With this Module, the following Fortran sample, named test4.f90, works
with ISO_C_BINDING compatible compilers:


----------------------------------------------------------------------------------------------------
PROGRAM TestProj
!
USE ISO_C_BINDING
USE libmyp
IMPLICIT NONE
!
type(C_PTR) :: SystemInPtr,SystemOutPtr
real(C_DOUBLE) :: x, y, z
INTEGER(C_INT) :: MyResult
!
! Initialize the coordinate systems
!
SystemInPtr = pj_init_plus('+proj=longlat +datum=WGS84 '//&
& '+ellps=WGS84 +towgs84=0,0,0'//char(0))

SystemOutPtr = pj_init_plus('+proj=ob_tran +o_proj=eqc '//&
& '+o_lat_p=30.0 +a=57.29578 +lon_0=0'//char(0))
!
! Read a point in lon-lat [degree], transform to [radians]
!
READ(*,*) x,y
WRITE(*,10) x,y
10 FORMAT('In: ',F15.5,1X,F15.5)

z = 0._C_DOUBLE

x = x * 0.0174533_C_DOUBLE
y = y * 0.0174533_C_DOUBLE
!
! Transform to shifted-pole 60 coordinates
!
MyResult = pj_transform(SystemInPtr,SystemOutPtr, 1, 0, x, y, z)
!
! Show results
!
WRITE(*,20) x,y
20 FORMAT('Out: ',F15.5,1X,F15.5)
!
END PROGRAM TestProj
----------------------------------------------------------------------------------------------------



My next step towards a working executable on our operational system
was to eliminate all references to ISO_C_BINDING.
As collateral damage I have to replace all the C-specific declarations
in my Fortran program to native Fortran types. I don't have a full
grasp of how to do that, but my biggest fear is for the things called
C_PTR. In the C-headerfile, these things live as type projPJ, defined
as follows:

#if !defined(PROJECTS_H)
typedef struct { double u, v; } projUV;
typedef void *projPJ;
#define projXY projUV
#define projLP projUV
#else
typedef PJ *projPJ;
# define projXY XY
# define projLP LP
#endif

I don't even know if the # symbols mean that these lines are comments,
or that they are compiler directives (or anything else).

I know that, during object code generation, Fortran subroutine names
get an underscore appended to distinguish them from C-routines. I
wrote C-wrapper-functions for the two C routines that I would like to
use: pj_init_plus and pj_transform. The C-sample above now also
compiles and runs with function names carrying an extra underscore.
Now I have to re-write the interface module libmyp.f90 and the main
Fortran program test4.f90.

I have no clue of how to proceed.

Can anyone give me a suggestion of the precise syntax for both the
Fortran module and for the main fortran program that would lead to a
working executable that uses the C library?

Thanks!


Arjan
 
F

Flash Gordon

Arjan said:
Hi!

On sister forum Comp.Lang.Fortran I had a discussion about connecting
Proj-4 (a coordinate transformation library, written in C) to my
Fortran project. I do now have a working connection, but it requires
the use of a module named ISO_C_BINDING. This module, which is part of
the F2003 standard, is not supported by the F95 compiler that will
produce our operational executable. Since the people on the Fortran
forum really have done their utmost to help me from their side, I
thought that maybe now you, with your background in C, could give it
the last push it needs.

We cam explain what the C does (to a degree) but I suspect that you will
need to ask in a group dedicated to your F95 & C compilers to find out
the specifics.

My next step towards a working executable on our operational system
was to eliminate all references to ISO_C_BINDING.

Which is probably what makes the Fortran compiler do things in a way
which is compatible with the way the C compiler works...
As collateral damage I have to replace all the C-specific declarations
in my Fortran program to native Fortran types.

You may well have just replaced the types that are compatible with the C
compiler with types which are incompatible!
I don't have a full
grasp of how to do that, but my biggest fear is for the things called
C_PTR. In the C-headerfile, these things live as type projPJ, defined
as follows:

#if !defined(PROJECTS_H)

#if is used for conditional compilation. The code below is compiled if
PROJECTS_H has not been defined (either using #define, possibly in some
other header file included directly or indirectly before this point, or
maybe by a compiler option controlled from a makefile)
typedef struct { double u, v; } projUV;
typedef void *projPJ;
#define projXY projUV
#define projLP projUV
#else

If it was defined then this is compiled.
typedef PJ *projPJ;
# define projXY XY
# define projLP LP
#endif

#define is effectively used to define textual replacement. So after this
each instance of projXY in the source code will be replaced with either
projUV or XY depending on whether or not PROJECTS_H had been defined.
I don't even know if the # symbols mean that these lines are comments,
or that they are compiler directives (or anything else).

Compiler directives, in effect. C has a pre-processor that is run before
the compiler is run...

OK, it can be all done by one program, and the pre-processor is not
normally directly run by you, and everything I've said is
simplification, but I don't think you want all the gory details.

Can anyone give me a suggestion of the precise syntax for both the
Fortran module and for the main fortran program that would lead to a
working executable that uses the C library?

You really do need to ask where they know the compilers you are
targetting. Before the Fortran standard standardised how the interfacing
was done it may well have varied from system to system, an no one who
does not use Fortran will know the details, an no one who does not know
your specific Fortran implementation will know the details for it!
Whatever you do may well not work on other implementations.
 
U

user923005

Hi!

On sister forum Comp.Lang.Fortran I had a discussion about connecting
Proj-4 (a coordinate transformation library, written in C) to my
Fortran project. I do now have a working connection, but it requires
the use of a module named ISO_C_BINDING. This module, which is part of
the F2003 standard, is not supported by the F95 compiler that will
produce our operational executable. Since the people on the Fortran
forum really have done their utmost to help me from their side, I
thought that maybe now you, with your background in C, could give it
the last push it needs.

My C-skills are utterly poor. The last serious code I wrote in C was
only a few hundreds of lines for my MSc thesis in the late 1980s.

My question is: how can I use the Proj-4 library libproj.a from within
my Fortran code, without using module ISO_C_BINDING?

A working C example, named test1.c, is:

---------------------------------------------------------------------------­-------------------------
#include "proj_api.h"
int p;
main(int argc, char **argv) {
     projPJ pj_HIRLAM6, pj_latlong;
     double x, y;
     if (!(pj_HIRLAM6 = pj_init_plus("+proj=ob_tran +o_proj=eqc
+o_lat_p=30.0 +a=57.29578 +lon_0=0")) )
        exit(1);
     if (!(pj_latlong = pj_init_plus("+proj=latlong +ellps=clrk66")) )
        exit(1);
     while (scanf("%lf %lf", &x, &y) == 2) {
        x *= DEG_TO_RAD;
        y *= DEG_TO_RAD;
        p = pj_transform(pj_latlong, pj_HIRLAM6, 1, 0, &x, &y, NULL );
        printf("%.2f\t%.2f\n", x, y);
     }
     exit(0);}

---------------------------------------------------------------------------­-------------------------

It compiles with: gcc test1.c -lproj -o test1.exe.

The Fortran sample using ISO_C_BINDING uses a Module named libmyp.f90
for the interfacing between C-library and Fortran-program:

---------------------------------------------------------------------------­-------------------------
MODULE LibMyP
!
! Module for interfacing between Proj-4 library libproj.a
! and Fortran. So far only pj_init_plus and pj_transform are
supported.
! More routines can be added in a similar way.
! Sample use:
!
! g95 libmyp.f90 testproj.f90 -lproj -o testproj.exe
!
! Formulate your compile statement with care!
! FIRST the sources, THEN the library-path and library!!
!
USE ISO_C_BINDING
IMPLICIT NONE
PRIVATE
PUBLIC :: pj_init_plus, pj_transform
!
INTERFACE
   FUNCTION pj_init_plus(name) BIND(C,NAME='pj_init_plus')
      USE ISO_C_BINDING
      IMPLICIT NONE
      TYPE(C_PTR) :: pj_init_plus
      CHARACTER(KIND=C_CHAR) :: name(*)
   END FUNCTION pj_init_plus

   FUNCTION pj_transform(src, dst, point_count, point_offset, &
     &   x, y, z) BIND(C,NAME='pj_transform')
      USE ISO_C_BINDING
      IMPLICIT NONE
      TYPE(C_PTR), VALUE :: src, dst
      INTEGER(C_LONG), VALUE :: point_count
      INTEGER(C_INT), VALUE :: point_offset
      INTEGER(C_INT) :: pj_transform
      REAL(C_DOUBLE) :: x, y, z
   END FUNCTION pj_transform
END INTERFACE
!
END MODULE LibMyP
---------------------------------------------------------------------------­-------------------------

With this Module, the following Fortran sample, named test4.f90, works
with ISO_C_BINDING compatible compilers:

---------------------------------------------------------------------------­-------------------------
   PROGRAM TestProj
!
   USE ISO_C_BINDING
   USE libmyp
   IMPLICIT NONE
!
   type(C_PTR) :: SystemInPtr,SystemOutPtr
   real(C_DOUBLE) :: x, y, z
   INTEGER(C_INT) :: MyResult
!
! Initialize the coordinate systems
!
   SystemInPtr = pj_init_plus('+proj=longlat +datum=WGS84 '//&
   & '+ellps=WGS84 +towgs84=0,0,0'//char(0))

   SystemOutPtr = pj_init_plus('+proj=ob_tran +o_proj=eqc '//&
   & '+o_lat_p=30.0 +a=57.29578 +lon_0=0'//char(0))
!
! Read a point in lon-lat [degree], transform to [radians]
!
   READ(*,*) x,y
   WRITE(*,10) x,y
 10 FORMAT('In:  ',F15.5,1X,F15.5)

   z = 0._C_DOUBLE

   x = x * 0.0174533_C_DOUBLE
   y = y * 0.0174533_C_DOUBLE
!
! Transform to shifted-pole 60 coordinates
!
   MyResult = pj_transform(SystemInPtr,SystemOutPtr, 1, 0, x, y, z)
!
! Show results
!
   WRITE(*,20) x,y
 20 FORMAT('Out: ',F15.5,1X,F15.5)
!
   END PROGRAM TestProj
---------------------------------------------------------------------------­-------------------------

My next step towards a working executable on our operational system
was to eliminate all references to ISO_C_BINDING.
As collateral damage I have to replace all the C-specific declarations
in my Fortran program to native Fortran types. I don't have a full
grasp of how to do that, but my biggest fear is for the things called
C_PTR. In the C-headerfile, these things live as type projPJ, defined
as follows:

#if !defined(PROJECTS_H)
    typedef struct { double u, v; } projUV;
    typedef void *projPJ;
    #define projXY projUV
    #define projLP projUV
#else
    typedef PJ *projPJ;
#   define projXY       XY
#   define projLP       LP
#endif

I don't even know if the # symbols mean that these lines are comments,
or that they are compiler directives (or anything else).

I know that, during object code generation, Fortran subroutine names
get an underscore appended to distinguish them from C-routines. I
wrote C-wrapper-functions for the two C routines that I would like to
use: pj_init_plus and pj_transform. The C-sample above now also
compiles and runs with function names carrying an extra underscore.
Now I have to re-write the interface module libmyp.f90 and the main
Fortran program test4.f90.

I have no clue of how to proceed.

Can anyone give me a suggestion of the precise syntax for both the
Fortran module and for the main fortran program that would lead to a
working executable that uses the C library?

http://www.ats.ucla.edu/clusters/common/computing/c-fortran-interop.html
http://alignment.hep.brandeis.edu/Software/Mixing_Manual.html
http://www.yolinux.com/TUTORIALS/LinuxTutorialMixingFortranAndC.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top