5

I have a large, mixed C/Fortran, code base, currently compiled using the Intel tools on Windows. I've been asked to port it to the GNU tools, on Linux. More or less at random, I've selected version 4.8.

Where a C function is called from Fortran, the interoperability often looks like this:

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

!Fortran code:
program test
implicit none
call printstr("Hello, world.")
end

The Intel Fortran compiler always generates upper-case symbols, so this works fine. But the GNU Fortran compiler always generates lower-case symbols and so there is a linker error.

The GNU Fortran compiler used to have an option called -fcase-upper which made it generate upper-case symbols, but it seems this was too configurable for everyone's good and it has been removed (I'm not exactly sure when).

It's possible to use the ISO_C_BINDING facility to force the compiler to generate a case-sensitive name:

program test
interface
subroutine printstr(str) bind(C, name='PRINTSTR')
character :: str(*)
end subroutine
end interface

call printstr("Hello, world.")
end

This resolves the linker error but it changes how string parameters are handled; the length parameter is no longer provided. So to use this method, I'd not only have to add interface definitions for every function that currently works this way, but I'd also have to change how strings are handled in every call to such a function, making sure that all strings are null-terminated.

I could go through and make all such functions lower-case, but of course the Intel compiler still generates upper-case symbols, so that would break the existing build.

Since there are ~2,000 such functions, that seems an infeasible amount of work. So, my question is this: How can I resolve the link errors without changing the function call semantics and without breaking the existing build using the Intel compilers?

Tom
  • 7,269
  • 1
  • 42
  • 69
  • I'm afraid a rather bigger problem you're going to have is that Intel passes the length as a `size_t`, whereas GFortran uses `int`. That's fine on 32-bit, but breaks horribly on 64-bit systems passing more than one string at a time, and it doesn't even get caught by the linker. – Tristan Brindle Oct 15 '14 at 05:06
  • I think, purely by good luck, I get away with that one. The Intel build is 32-bit. – Tom Oct 15 '14 at 05:09
  • I think (possibly) the compiler which had `-fcase-upper` was g95, not GFortran (which is now the official GNU Fortran compiler). AFAIK g95 is still developed, albeit at a slower pace than GFortran, but if your codebase is pure F77/F95 and doesn't use cutting edge F2003/F2008 features, it may be worth looking into? – Tristan Brindle Oct 15 '14 at 05:19
  • Are these indeed ~2000 different functions interfacing from Fortran to C? Or are these only calls to a few functions with differing arguments? In the latter case, you could simply write some wrappers, which append the `C_NULL_CHAR` for you. – Stefan Oct 15 '14 at 05:30
  • On a closer look, many of my (several thousand) linker problems are unrelated to this. There are 244 different functions interfacing from Fortran to C, called 410 times. So it's not 2,000, but its not a trivial effort to fix them all, either. – Tom Oct 15 '14 at 05:50

1 Answers1

2

To solve the linker error you can do it other way around. Use Intel compiler option names to convert external names to lowercase to match the default GNU Fortran option. And convert name in to lowercase too:

void printstr(char *str, size_t len) {...}

Personally I would recommend using -funderscoring and Intel's /assume:underscore to distinguish functions that are intended for interoperability.

// C code:
void printstr_(char *str, size_t len) {...}

!Fortran code:
program test
implicit none
call printstr("Hello, world.")
end
Peter Petrik
  • 9,701
  • 5
  • 41
  • 65