Feature #1108

a proposal for GMT F77 Interface

Added by Masakazu 6 months ago. Updated about 1 month ago.

Status:ResolvedStart date:2017-06-06
Priority:LowDue date:
Assignee:Paul% Done:

100%

Category:-
Target version:Candidate for next bugfix release
Platform:

Description

Dear all,

I am interested in using the GMT Fortran 77 interface described in http://gmt.soest.hawaii.edu/doc/latest/GMT_API.html#fortran-77-grid-i-o, and found following two issues when I tried to use them. Here I would like to propose a patch (gmt5_f77.patch) to address them.

  • names of interface functions
    When compiling the sample program gmt_f77_test.f90 with GNU Fortran (gfortran), I got the following result:
    $ gfortran gmt_f77_test.f90 `/usr/bin/gmt-config --libs`
    /tmp/ccrrguQF.o: In function `MAIN__':
    gmt_f77_test.f90:(.text+0x3c2): undefined reference to `gmt_f77_writegrd_'
    gmt_f77_test.f90:(.text+0x612): undefined reference to `gmt_f77_readgrdinfo_'
    gmt_f77_test.f90:(.text+0xa9b): undefined reference to `gmt_f77_readgrd_'
    collect2: error: ld returned 1 exit status
    With Intel Fortran (ifort) and Oracle Solaris Studio, I had the same result. Even if we write "call GMT_F77_writegrd(...)" in a Fortran source code, (most of) Fortran compilers generate a symbol name "gmt_f77_writegrd_" in the object file, because Fortran is generally case-insensitive. Therefore, I think the names of the F77 interface functions in gmt_api.c should be "gmt_f77_writegrd_" (lowercase) rather than "GMT_F77_writegrd_". In addition, some other Fortran compilers use different symbol name conventions such as "GMT_F77_WRITEGRD", etc. In order to support them, I add wrapper functions in the patch attached.
  • Treatment of character strings
    Fortran and C treat character strings in different ways. Since C assumes a string has an end mark '\0', while Fortran does not, the interface functions had better to absorb the difference. Besides, Fortran adds an additional "int" argument to the argument list of the function when a character string exists in the argument list of a function, as explained in https://gcc.gnu.org/wiki/GFortranGettingStarted#Compiling_a_mixed_C-Fortran_program_.28main_program_is_Fortran.29. I also include the treatment for those things to the patch.

By applying the patch to GMT-5.4.1, I can compile and link the sample Fortran program with libgmt.so.
I would be grateful if you could review whether the patch is applicable to GMT. Thank you.

gmt_f77_test.f90 (1.34 KB) Masakazu, 2017-06-06 18:35

gmt5_f77.patch Magnifier (9.19 KB) Masakazu, 2017-06-06 18:47

gmt5_f77.planB.patch Magnifier (5.26 KB) Masakazu, 2017-06-08 04:42

gmt5_f77.planB.updated.patch Magnifier - updated version of "Plan B" patch against GMT-5.4.1 (5.19 KB) Masakazu, 2017-06-08 19:29

gmt_f77_test.f90 - update version of F77 interface test (1.67 KB) Masakazu, 2017-06-08 19:30

gmt_fapi_grd_test.f90 - test for GMT-FORTRAN-API (1.64 KB) Masakazu, 2017-06-08 19:30

Associated revisions

Revision 18330
Added by Paul 6 months ago

Address issue #1108

History

#1 Updated by Paul 6 months ago

  • Status changed from New to Resolved
  • Assignee set to Paul
  • Target version set to Candidate for next bugfix release
  • % Done changed from 0 to 100

Thanks, should be addressed in r18331. I made some minor changes (the STRNCPY needs to be used in all three functions) but basically what you wrote. Compiles for me too. If you are interested in more than those three i/o functions then see http://gmt.soest.hawaii.edu/projects/gmt-fortran-api as well as the whole API if you compile with -DFORTRAN_API (see gmt_api.c for this). Obviously, none of us have really tried to use the GMT API from Fortran.

#2 Updated by Masakazu 6 months ago

I really appreciate for your very quick response.

I made some minor changes (the STRNCPY needs to be used in all three functions) but basically what you wrote.

In gmt_f77_readgrd_ and gmt_f77_readgrdinfo_, aren't the source and destination of strings opposite? ("header.title" should be copied to "title" in order to pass the string to Fortran)

--- gmt_api.c.orig    Wed Jun  7 17:15:20 2017
+++ gmt_api.c    Wed Jun  7 17:19:34 2017
@@ -10476,8 +10476,8 @@
     limit[ZLO] = header.z_min;
     limit[ZHI] = header.z_max;
     dim[GMT_Z] = header.registration;
-    if (title) F_STRNCPY (header.title, title, GMT_GRID_TITLE_LEN80, ltitle);
-    if (remark) F_STRNCPY (header.remark, remark, GMT_GRID_REMARK_LEN160, lremark);
+    if (title) F_STRNCPY (title, header.title, ltitle, GMT_GRID_TITLE_LEN80);
+    if (remark) F_STRNCPY (remark, header.remark, lremark, GMT_GRID_REMARK_LEN160);

     if (GMT_Destroy_Session (API) != GMT_NOERROR) return GMT_RUNTIME_ERROR;
     return GMT_NOERROR;
@@ -10532,8 +10532,8 @@
     limit[ZLO] = header.z_min;
     limit[ZHI] = header.z_max;
     dim[GMT_Z] = header.registration;
-    if (title) F_STRNCPY (header.title, title, GMT_GRID_TITLE_LEN80, ltitle);
-    if (remark) F_STRNCPY (header.remark, remark, GMT_GRID_REMARK_LEN160, lremark);
+    if (title) F_STRNCPY (title, header.title, ltitle, GMT_GRID_TITLE_LEN80);
+    if (remark) F_STRNCPY (remark, header.remark, lremark, GMT_GRID_REMARK_LEN160);

     if (GMT_Destroy_Session (API) != GMT_NOERROR) return GMT_RUNTIME_ERROR;
     return GMT_NOERROR;

#3 Updated by Paul 6 months ago

Sorry about that - went too fast with the copy/paste. Fixed in r18333.

#4 Updated by Masakazu 6 months ago

Thank you for the fix. I tested the fix r18333 and before on our computer, and have confirmed that it works as expected.

By the way, I notice this fix causes an incompatibility in gmt-fortran-api:source:trunk/src/gmt.f90@27#L821 in which the function names such as "GMT_F77_writegrd_" are still assumed. I am sorry for not considering the side effect.
I think it may be fixed by removing (or commenting out) bind(c,name='...') attributes from gmt.f90 as follows:

--- a/src/gmt.f90
+++ b/src/gmt.f90
@@ -820,5 +820,5 @@ interface
 ! ----------------------------------
-! int GMT_F77_readgrdinfo_(unsigned int dim[], double wesn[], double inc[], char *title, char *remark, char *file);
+! int gmt_f77_readgrdinfo_(unsigned int dim[], double wesn[], double inc[], char *title, char *remark, const char *file, int ltitle, int lremark, int lfile);
 ! ----------------------------------
-integer(c_int) function GMT_F77_readgrdinfo(dim,wesn,inc,title,remark,file) bind(c,name='GMT_F77_readgrdinfo_')
+integer(c_int) function GMT_F77_readgrdinfo(dim,wesn,inc,title,remark,file) !bind(c,name='gmt_f77_readgrdinfo_')
 import c_int,c_float,c_double,c_char
@@ -829,5 +829,5 @@ end function
 ! ----------------------------------
-! int GMT_F77_readgrd_(float *array, unsigned int dim[], double wesn[], double inc[], char *title, char *remark, char *file);
+! int gmt_f77_readgrd_(float *array, unsigned int dim[], double wesn[], double inc[], char *title, char *remark, const char *file, int ltitle, int lremark, int lfile);
 ! ----------------------------------
-integer(c_int) function GMT_F77_readgrd(array,dim,wesn,inc,title,remark,file) bind(c,name='GMT_F77_readgrd_')
+integer(c_int) function GMT_F77_readgrd(array,dim,wesn,inc,title,remark,file) !bind(c,name='gmt_f77_readgrd_')
 import c_int,c_float,c_double,c_char
@@ -839,5 +839,5 @@ end function
 ! ----------------------------------
-! int GMT_F77_writegrd_(float *array, unsigned int dim[], double wesn[], double inc[], char *title, char *remark, char *file);
+! int gmt_f77_writegrd_(float *array, unsigned int dim[], double wesn[], double inc[], const char *title, const char *remark, const char *file, int ltitle, int lremark, int lfile);
 ! ----------------------------------
-integer(c_int) function GMT_F77_writegrd(array,dim,wesn,inc,title,remark,file) bind(c,name='GMT_F77_writegrd_')
+integer(c_int) function GMT_F77_writegrd(array,dim,wesn,inc,title,remark,file) !bind(c,name='gmt_f77_writegrd_')
 import c_int,c_float,c_double,c_char

#5 Updated by Remko 6 months ago

Dear Masakazu,
You are right about the conversion to lowercase. We should implement that. But notice that you had to remove the "bind" parts in the Fortran code, which are exactly designed to avoid the addition of the integer arguments and other incompatibilities between Fortran and C, as well as providing a compiler-independent interface.
So, while your solution works for "old Fortran" it would be different in "new Fortran" (i.e., with the bind parts).
I think that all that would have had to be done was to
  • Make lowercase function names (this for sure would improve compatibility)
  • Flip the two arguments in F_STRNCPY (this indeed looks incorrect)
    This would mean we will probably have to revert some of the changes.

#6 Updated by Masakazu 6 months ago

Dear Remko, thank you very much for the explanation. I understand that my previous comment

it may be fixed by removing (or commenting out) bind(c,name='...') attributes from gmt.f90

is too naive and not a good idea.

I am thinking about "Plan B" in order to support both "old" and "new" Fortran features. The strategy of "Plan B" would be:
  • Revert gmt_api.c, leaving GMT_F77_*grd*_() unchanged
    • this means that GMT-FORTRAN-API does not need to be changed.
  • and then add gmt_f77_*grd*_() wrapper functions for "old Fortran" that call GMT_F77_*grd*_() and that address the lowercase issue and the string issue.

For your reference, I attach the provisional "Plan B" patch gmt5_f77.planB.patch. Please note that it has not been well tested yet. Your comments on it would be appreciated.

#7 Updated by Paul 6 months ago

Thanks Remko and Masakazu for looking into this.
I will try to stay out of this since I don't use Fortran so don't want to mess anything up that I am not able to test.

#8 Updated by Masakazu 6 months ago

For your reference, I attach the provisional "Plan B" patch gmt5_f77.planB.patch. Please note that it has not been well tested yet...

I revised the "Plan B" patch (gmt5_f77.planB.updated.patch), and have checked it on my environment. So far it seems working correctly with "old" Fortran interface, without any side effects to GMT/FORTRAN API ("new" Fortran interface).
I would appreciate if you could check the proposed patch.

#9 Updated by dan about 1 month ago

(Spam removed)

Also available in: Atom PDF