- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm in charge of a rather large C-Fortran interface for our codes that has recently run afoul of the extra strictness included in 11+.
"error #8532: A character dummy argument with length other than 1 is not interoperable"
This problem has previously been raised by a coworker in 2011. Unfortunately, the answer given does not solve the real problem at hand (mostly because the co-worker was just trying to solve one specific issue and not the entire issue). I also understand that the old solution operated in a gray area, however, the implementation met all of the requirements imposed by operation in this gray area.
Problem Description
- Large C library with 100+ API entry points.
- Almost all of them include string arguments (90% IN, some are OUT)
- This library was previously written in Fortran.
- Thousands of lines in 50-60 Fortran executables which call the C library assuming it is still Fortran.
- The C Library includes the necessary logic to "pretend" to be Fortran (supports pretending to be CVF, IVF, and gfortran)
- The C Library provides an optional auto-generated module with the interface/subroutine/BIND magic to give argument type/dimension checking to these codes.
Example C API method
/* "data" is scalar to 7D, any of the primitive fortran types */ ABC_API(void) foobar ( IN int *id, IN const char *folder FDECL_LENGTH_MIXED(folder), IN const char *file FDECL_LENGTH_MIXED(file), IN_BUFFER_ANY const void *data, IN_ESIZE(10) const int descriptor[], IN int *count, IN_ESIZE_MAX(7) const int startingElement[], OUT_ESIZE(2) int status[] FDECL_LENGTH_AFTER(folder) FDECL_LENGTH_AFTER(file) );
Example Fortran Module entry for that routine (snipped for brevity)
! toplevel foobar selects type/dimension call interface foobar module procedure foobar_i0, foobar_i1, foobar_i2, foobar_i3, foobar_i4, foobar_i5, foobar_i6, foobar_i7 & , foobar_r0, foobar_r1, foobar_r2, foobar_r3, foobar_r4, foobar_r5, foobar_r6, foobar_r7 & , foobar_d0, foobar_d1, foobar_d2, foobar_d3, foobar_d4, foobar_d5, foobar_d6, foobar_d7 & , foobar_cx0, foobar_cx1, foobar_cx2, foobar_cx3, foobar_cx4, foobar_cx5, foobar_cx6, foobar_cx7 & , foobar_l0, foobar_l1, foobar_l2, foobar_l3, foobar_l4, foobar_l5, foobar_l6, foobar_l7 & , foobar_c0, foobar_c1, foobar_c2, foobar_c3, foobar_c4, foobar_c5, foobar_c6, foobar_c7 endinterface foobar ! top level generic interface selects one of the following, which calls the C binding routines subroutine foobar_i0 ( id, folder, file, idata, dsdes, ne, selem, istat ) implicit none integer, intent(in) :: id character(len=*), intent(in) :: folder character(len=*), intent(in) :: file integer, intent(in) :: idata integer, intent(in) :: dsdes(DSDES_COUNT) integer, intent(in) :: ne integer, intent(in) :: selem(*) integer, intent(out) :: istat(STAT_COUNT) call foobar_internal_i0(id, folder, file, idata, dsdes, ne, selem, istat) endsubroutine foobar_i0 subroutine foobar_i1 ( id, folder, file, idata, dsdes, ne, selem, istat ) implicit none integer, intent(in) :: id character(len=*), intent(in) :: folder character(len=*), intent(in) :: file integer, intent(in) :: idata(:) integer, intent(in) :: dsdes(DSDES_COUNT) integer, intent(in) :: ne integer, intent(in) :: selem(*) integer, intent(out) :: istat(STAT_COUNT) call foobar_internal_i(id, folder, file, idata, dsdes, ne, selem, istat) endsubroutine foobar_i1 ! repeat subroutine foobar_XYZ for each type and dimension
! These _internal_ variants are the methods actually bound to the C, which provide both Scalar and ! DIMENSION(*) versions so that C just gets a raw pointer subroutine foobar_internal_c ( id, folder, file, cdata, dsdes, ne, selem, istat ) bind(C, name='FOOBAR') implicit none integer, intent(in) :: id character(len=*), intent(in) :: folder character(len=*), intent(in) :: file character(len=*), intent(in) :: cdata(*) integer, intent(in) :: dsdes(DSDES_COUNT) integer, intent(in) :: ne integer, intent(in) :: selem(*) integer, intent(out) :: istat(STAT_COUNT) endsubroutine foobar_internal_c subroutine foobar_internal_c0 ( id, folder, file, cdata, dsdes, ne, selem, istat ) bind(C, name='FOOBAR') implicit none integer, intent(in) :: id character(len=*), intent(in) :: folder character(len=*), intent(in) :: file character(len=*), intent(in) :: cdata integer, intent(in) :: dsdes(DSDES_COUNT) integer, intent(in) :: ne integer, intent(in) :: selem(*) integer, intent(out) :: istat(STAT_COUNT) endsubroutine foobar_internal_c0 ! repeat foobar_internal_XYZ for each type
Basically, I can't update the C code (and its API) in any manner which would break the expectation that it is "Fortran". Now I'm caught because 11+ no longer allows this behavior. I also cannot introduce any required shim code on the Fortran side, because the API must work with or without the auto-generated module.
I'm more than happy to maintain the headache of the C side understanding Fortran string-isms, etc. This is far easier than introducing C-isms to the Fortran side, in both code support AND time-burden to update/verify all of the production Fortran.
Is there a way I can update this interface to meet both my desire to: (a) provide a type checking solution for the library, and (b) not introduce any required shimming?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You can switch off error #8532 if you wish
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
app4619 wrote:
You can switch off error #8532 if you wish
Not per my tests:
Cannot disable Fortran error message 8532
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Christopher Watford wrote:
I'm in charge of a rather large C-Fortran interface for our codes that has recently run afoul of the extra strictness included in 11+.
"error #8532: A character dummy argument with length other than 1 is not interoperable"
This problem has previously been raised by a coworker in 2011. Unfortunately, the answer given does not solve the real problem at hand (mostly because the co-worker was just trying to solve one specific issue and not the entire issue). I also understand that the old solution operated in a gray area, however, the implementation met all of the requirements imposed by operation in this gray area.
...
Basically, I can't update the C code (and its API) in any manner which would break the expectation that it is "Fortran". Now I'm caught because 11+ no longer allows this behavior. I also cannot introduce any required shim code on the Fortran side, because the API must work with or without the auto-generated module.
I'm more than happy to maintain the headache of the C side understanding Fortran string-isms, etc. This is far easier than introducing C-isms to the Fortran side, in both code support AND time-burden to update/verify all of the production Fortran.
Is there a way I can update this interface to meet both my desire to: (a) provide a type checking solution for the library, and (b) not introduce any required shimming?
Instead of "auto-generated module with the interface/subroutine/BIND magic to give argument type/dimension checking to these codes" from the C library, can you create a concrete Fortran wrapper module that has wrapper procedures which translate "CHARACTER(LEN=*) :: " arguments from all the user Fortran code to "CHARACTER(LEN=1) :: var(*)" in the calls to the actual C code? The Fortran users then only need to "USE" this wrapper module.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was about to say that you probably can't meet your requirements without wrapper procedures, but given that you already have (I hope automatically generated) wrapper procedures, are you allowed to just change them? For example, in your foobar_i0 subroutine, change
call foobar_internal_i0(
id
, folder,
file
, idata, dsdes, ne, selem, istat)
to
call foobar_internal_i0(
id
, folder,
file
, idata, dsdes, ne, selem, istat, LEN(folder), LEN(file))
and then foobar_internal_i0 will read
subroutine foobar_internal_i0 ( id, folder, file, idata, dsdes, ne, selem, istat, folder_LEN, file_LEN ) bind(C, name='FOOBAR') implicit none integer, intent(in) :: id character, intent(in) :: folder(*) character, intent(in) :: file(*) integer, intent(in) :: idata integer, intent(in) :: dsdes(DSDES_COUNT) integer, intent(in) :: ne integer, intent(in) :: selem(*) integer, intent(out) :: istat(STAT_COUNT) integer, intent(in) :: folder_LEN integer, intent(in) :: file_LEN endsubroutine foobar_internal_i0
Also you could save on writing out so many wrappers and interface bodies if you wrote out a template that worked for all data types (requires implicit typing for the template type). I guess there's a little problem for character data because you don't really want a C interface for a scalar character dummy argument here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You misunderstand the nature of the problem. There is no "extra strictness". You are, in some of the interfaces, using the C interoperability features of Fortran 2003. When you say BIND(C) for a routine interface, the standard places restrictions on the dummy arguments. One of these is that one about character lengths greater than 1. If this library creates auto-generated Fortran interfaces with BIND and with CHARACTER(*), then it is simply wrong.
There is a solution - remove bind(C) as it's clear from your text that the C code is not suitable for this. Use
!DEC$ ATTRIBUTES DECORATE, ALIAS:"c-routine-name" :: functionname
to get the name the way you want it. If you do this, then the character lengths are passed at the end of the argument list as hidden arguments.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In my gfortran-centric solution, I forgot to give the LEN parameters the VALUE attribute:
integer(C_SIZE_T), VALUE :: folder_LEN
integer(C_SIZE_T), VALUE :: file_LEN
The KIND of the hidden length arguments is a bit up in the air: ifort specifies C_SIZE_T (from ISO_C_BINDING) but gfortran used to use KIND(0) although I think there was supposed to be a change to C_SIZE_T but if they did make the change over, they didn't document it. But given the way arguments are passed in 64-bit ABIs it shouldn't really matter. I think my approach should work in two of the target compilers, gfortran and ifort, whereas Steve's approach should work in ifort and CVF. Except ... CVF didn't have DECORATE, did it? I am more fond of using BIND(C) to solve interface issues because the rules for !DEC$ ATTRIBUTES are a bit arcane and inconsistent and only partially documented.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel (Intel) wrote:
You misunderstand the nature of the problem. There is no "extra strictness".
Perhaps I would have been better to word it as "now enforcing"! I'm going to attempt the decoration solution as that seems like a much easier solution.
Thank you all for the help.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There may have been a compiler bug in version 10, where we first introduced BIND(C), that it did not do what the standard required.That was a long time ago.
I agree with RO that BIND(C) is generally preferable, but the C library being used here is expressly written in a way not compatible with BIND(C) so I suggested the alternative. (If you didn't mind changing the Fortran code to explicitly pass the character lengths and modified the interfaces to include them, then one could use BIND(C).)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
CVF 6.6a does support DECORATE; I don't know about earlier versions.
![](/skins/images/B7BA37F9CE4B52FF7CAE1FB0388839C8/responsive_peak/images/icon_anonymous_message.png)
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page