GNU Fortran - control character

Is there a way to handle the case of characters released by GNU Fortran 4.8?

In earlier versions (e.g. 3.4) there were -fcase-lower , -fcase-preserve and -fcase-upper to force the lower case, the case used in the source and upper case respectively, but they seem to have been dropped. Is there a new way to control this?

Edit

I am trying to port a large mixed C / Fortran code base from Intel compilers to GNU compilers.

I know that we can use BIND(C, name='...') to indicate the symbol name for a particular case. However, this has other consequences. Consider this C function:

 void print(char *str, size_t len) { for(int ii = 0; ii < len; ii++) { putchar(str[ii]); } putchar('\n'); } 

We can call it from the Fortran program as follows:

 program test implicit none interface subroutine printstr(str) character :: str(*) end subroutine end interface call printstr("Hello, world."); end 

If the name of the C function is not all lowercase ( PrintStr , say), we can try to fix the Fortran program as follows:

 program test implicit none interface subroutine printstr(str) bind(C, name='PrintStr') use iso_c_binding character :: str(*) end subroutine end interface call printstr("Hello, world."); end 

This does not work, because bind(C, ...) changes the way the string parameter is processed and the length parameter is no longer provided (I'm not sure if this will damage the stack or simply overflow the buffer - always segfaults from the buffer overflow set as an example).

I think that probably the time has come for a new question on how to figure this out.

+5
source share
3 answers

Here is one way to get closer to this using the Fotran iso_c_binding module.

Firstly, the C code, as in your example:

 void PrintStr(char *str, size_t len) { for (int ii=0; ii < len; ++ii) putchar(str[ii]); putchar('\n'); } 

and the Fortran interface suitable for it:

 interface subroutine printstr_c(str, len) bind(C, name='PrintStr') use iso_c_binding, only: c_char, c_size_t implicit none character(kind=c_char) :: str(*) integer(c_size_t),value :: len end subroutine printstr_c end interface 

This will allow you to call the C function as:

 character(len=20) :: string = 'Hello ISO C env!' call printstr_c(string, int(len(string),kind=c_size_t)) 

This works, but requires the length argument to be specified explicitly. We can do a little better and create a Fortran wrapper around it to hide the length from the callers.

 subroutine printstr(str) use iso_c_binding, only: c_size_t implicit none character(len=*) :: str call printstr_c(str, int(len(str),kind=c_size_t)) end subroutine 

Now we can just call:

 character(len=20) :: string = 'Hello ISO C env!' call printstr(string) 

Note that I was not worried about null-terminating the string, since your C function loops over the length argument. If you need a null terminator, you can add it to the printstr routine.


If you have a lot of such functions that you want to call, all forms of void f(str, len) , then we can do a little more work and abstract the printstr function even more, just to be a universal translator from Fortran character variables to a pair char, len variables suitable for calling iso_c_binding. Consider this example:

 module cfuncs implicit none interface ! this interface is for an actual C function subroutine printstr_c(str, len) bind(C, name='PrintStr') use iso_c_binding, only: c_char, c_size_t implicit none character(kind=c_char) :: str(*) integer(c_size_t),value :: len end subroutine printstr_c end interface end module module ffuncs use cfuncs implicit none interface ! this interface is to constrain procedures passed to printstr() subroutine string_and_len(str, len) use iso_c_binding, only: c_char, c_size_t implicit none character(kind=c_char) :: str(*) integer(c_size_t),value :: len end subroutine string_and_len end interface contains ! this routine takes the C function you want to call and a string to pass ! and does the translation to call funct(str,len) subroutine printstr(func,str) use iso_c_binding, only: c_size_t implicit none procedure(string_and_len) :: func character(len=*) :: str call func(str, int(len(str),kind=c_size_t)) end subroutine end module program main use ffuncs implicit none character(len=20) :: string = 'Hello ISO C env!' call printstr(printstr_c, string) end program 

This may be a little redundant for this particular example, but it allows one Fortran shell to invoke many C functions of the same type signature. This, in turn, would only have to decorate Fortran calls in the code you ported to be wrapped with a wrapper function. For example, assuming printstrc_c is an external interface:

 ! old F77 non iso_c_binding call call printstr_c("Hello World") 

turns into

 ! wrapping the old F77 call through our Fortran wrapper handling iso_c_binding call printstr(printstr_c, "Hello World") 

It is not as elegant as the old way you did it, but the new versions of gfortran (3.x gcc were g77, and 4.x gfortran, afaik - complete rewriting) did not seem to be able to force a case save. If you wanted to avoid the clutter I demonstrated, another option would be to post processed Fortran compiled objects before binding and rewrite the function names to have a suitable case, but I would find it worse to work with (and a dirty hack) .

+2
source

Gfortran lacks the corresponding command line option. At the same time, GFortran supports the ISO_C_BINDING function, so you can rename characters to what is valid in C, for example:

 subroutine foo (a) bind(C, name="FoOoF") use iso_c_binding integer(C_int) :: a a = 42 end subroutine foo 
0
source

A partial and somewhat unsatisfactory answer, but the best we have found so far.

We searched high and low for this feature. In particular, to save the case WITHOUT Bind'C. The extreme “push” imposed by the authorities, which must insist on Bind'C, is a terrible result for many important circumstances, and especially for outdated code, and especially on Windows.

There is no way CHEAP can port legacy or mixed Intel and mixed language code to gFortran because, as far as we can tell, many years ago the GNU Fortran keepers clearly decided that they would not store the “save file” or anything else (I forgot the report about error, but you can search for it). Oddly enough, their excuse for abandoning these functions was that there was no interest ... I must say that it sounds a little ridiculous, since anyone who works in a mixed language environment on Windows almost certainly needs a save object with high frequency. This is required in VBA / Fortran for the DLL needed to access WinAPI s / r, etc., and where Bind'C / ISO causes more problems than patches.

... sometimes it seems that the GNU Fortran custodians live mostly on Linux, and in some cases express open hostility towards Windows ... which may be part of the problem.

Similarly, they decided NOT to have ALIAS or something like this attribute in compiler directives.

Thus, the only mechanism in gFortran (which we know) that allows us to save the register is Bind'C, which is a DISASTER for a number of reasons, especially for transmitting fixed len strings of len> 1.

We use two different and very unsatisfactory styles of solutions for mixed lang / interop with gFortran:

1) The case SHOULD BE CARRIED OUT, for example, when interacting with WinAPI:

 Interface ! Function w32_GetWindowTextW(hWnd, lpString, nMaxCount) bind(C,name="GetWindowTextW") ! ! from c:\Windows\System32\User32.dll ! Use, Intrinsic :: ISO_C_BINDING, Only: c_IntPtr_t, c_Size_t, c_Int, c_Ptr, c_Char ! !GCC$ ATTRIBUTES STDCALL :: w32_GetWindowTextW, hWnd, lpString, nMaxCount ! Integer(c_Int) :: w32_GetWindowTextW Integer(c_IntPtr_t), Value :: hWnd ! NOTE: this is SUPPOSED TO BE a Win HANDLE, this seems ISO equivalent Character(Kind=c_Char) :: lpString(*) Integer(c_Int), Value :: nMaxCount ! NOTE: this is SUPPOSED TO BE WinAPI int type, this seems ISO equivalent End Function w32_GetWindowTextW ! End Interface 

A save case is necessary here, because otherwise the interface will not find the entry point to WinAPI. Bind'C also allows aliasing, which for some strange reason is not available, with GCC FPP.

GCC compiler directives are needed to overcome the destruction / modification of the Bind'C calling convention and return it to STDCALL, as required by WinAPI (as well as with VB, Excel / VBA, etc.).

However, look at the "dog breakfast" needed to work with lpString var, where it should now be a vector or Len = 1. This is a very expensive rewrite (and not only in ads, but everywhere where these vars are used, at least an extra layer must be added to convert the array Len = 1 char to the original fixed len char vars).

2) The case where it would be “good” to keep case, but “cheaper” to use all lower case, for example, using VBA / Fortran interop to create DLLs as Excel add-ins.

ASIDE: the following depends on the erf custom implementation in our own libraries, but pretty good is available as internal.

You can go Bind'C and save the register (with all the "string consequences"), for example

 Function Erf_Math_BindC_XL(x) bind(C,name="Erf_Math_BindC_XL") ! Use ARTMathFuncsMod, Only: MathErf ! Proprietary alternative to Fortran2008 intrinsic Erf() ! !GCC$ ATTRIBUTES DLLEXPORT, STDCALL :: Erf_Math_BindC_XL ! Real*8 :: Erf_Math_BindC_XL ! Real*8, Intent(In) :: x ! Erf_Math_BindC_XL = MathErf(x) ! End Function Erf_Math_BindC_XL 

For comparison, you can use instead:

 Function Erf_Math_XL(x) ! Use ARTMathFuncsMod, Only: MathErf ! Proprietary alternative to Fortran2008 intrinsic Erf() ! !GCC$ ATTRIBUTES DLLEXPORT, STDCALL :: Erf_Math_BindC_XL ! Real*8 :: Erf_Math_XL ! Real*8, Intent(In) :: x ! Erf_Math_XL = MathErf(x) ! End Function Erf_Math_XL 

However, if you compile it directly using gFortan, the entry name will be styled and will look something like _erf_math_xl@4 .

So, if you already have a VBA declaration based on "Erf_Math_XL", then it will fail.

Now you can either rewrite the entire side of VBA ... very expensive, and "@nn" changes every time you change the arg list, so it is actually "geometrically more expensive."

In contrast, if you use -fno-underscore and -mrtd on the gFortran side, then the record names will simply be erf_math_xl . Good, so this is not a surviving case, but they are all lowercase, and "unecorated". This can be handled in a less costly way than rewriting many fixed len strings for len = 1 arrays, etc.

Then, on the VBA side, the Function / Sub declaration resolves ALIAS, so the “problem with the case” is a relatively simple “edit / replace macro”

... if anyone knows a better way, please comment.

HOWEVER, the really obvious and massively useful result would be something like the “keep case” or “MOST ESPECIALLY” switch, ALIAS option in FPP ATTRIBUTES

... not sure how to organize an "en mass" organization to encourage GNU Fortran coders to create this, but will be happy to help.

PS. If we were in the “conspiracy theory camp”, we would be wondering if Intel would “apply some influence”, because at the moment the gFortran mechanism is simply not able to fully convert the DEC / CVF / IVF compiler directives, etc. For example, if the ALIAS attribute existed, it is very likely that most / all of the DEC / CVF / IVF code could be GCC'd with relative ease, and this would probably cause a lot of migration for Intel Fortran and, thus, significant "cash migration from Intel" ... just a thought :-).

Interestingly, a few years ago, the Justice Department found Intel guilty of various “hindering competition,” etc., and was hit with a fine of $ 10 million / punishment for them ... so maybe this is not a very distant choice. to consider such possibilities.

-1
source

Source: https://habr.com/ru/post/1204629/


All Articles