CC (via f2c) compiling question using 2 libraries: undefined reference to 'int8_' etc

I’m still trying to convert a Fortran program plus its libraries to C code using the f2c program. When I use the below command to compile everything together, the routine calls in library1.a can’t find two routines in library2.a, plus I’m getting undefined reference to ‘int8_’ with library1.a. What do I do? I’m on a Red Hat Linux 7 64 bit computer.

I tried moving the libraries around in the command without success.
I also tried to put -l (and -L) in front of each library path without success.
I tried using library*.a instead of library1.a and library2.a without success.

There wasn’t any problem in the original Fortran program when gfortran linked to the libraries.

cc -o weather snow.c hail.c sleet.c library1.a library2.a -DLINUX -DSYSV -DNOHLA -g -Wall -Werror -fmax-errors=100 -lgfortran -lpthread -L/opt/libf2c -lf2c -lm

I’m going to try to put everything into one library.

Can you find a function in the source code for library1 that is called int8 or int8_? It may be an erroneous conversion. You do not provide any details about the routines in lbrary2 that it cannot find. Could there be a naming/conversion issue here as well?

You insist on converting the Fortran code to C, but interfacing between Fortran and C is so much easier and standard nowadays that it seem to me that you need very good reasons for doing all this, especially as the original program builds fine.

1 Like

Well, the integer*8 declaration is an extension, popular perhaps, but still an extension. You should use the KIND= attribute:

integer(kind=8) :: xyz   ! Preferably one of the various methods to parametrise the literal value!

Then to convert the value to the right type and kind, you can use:

xyz = int(rst, kind=8)

Now the compiler expects a function INT8 and you would have to define it.

The extra underscore is a typical decoration that Fortran compilers use to avoid conflicts with system libraries. I have seen a problem once with a compiler that did not do that by default. The program had a routine called EXIT that printed a message to the console and then STOPped. Guess what system routine was called to implement the STOP statement? Double points for describing what happened next.

That said, you will have to post some code, as now we can only guess when these extra underscores are introduced…

Because he is using f2c he cannot use Fortran 90 style declarations. f2c is essentially F77 plus MIL-STD 1753.

It is common for Fortran compilers to use name mangling, a modification of procedure names two ensure consistency with the standard and avoid conflicts with the system library. In f2c's case it converts all procedure names to a uniform case to deal with Fortran’s case insensitivity, and appends an underscore.

First ensure that no Fortran defined procedures end in an underscore. Appending an underscore to a procedure is against the F77 standard and may cause problems porting the code, In any C code intended to call the Fortran code translated to C use the proper casing and append the underscore.

Second INT8 is a gfortran extension that is is not provided by f2c. gfortran's name mangling has to deal with all the complexities of F2018 and is probably different from that of f2c. The result is that there is probably no INT8_ in gfortran's library. You will probably have to write your own INT8_ in C as I don’t think it can be written in F77 pus the MIL-STD 1753 extensions.

Third if you create your own INT8_ declare the returned type of INT8 in the calling code and also declare it to be EXTERNAL.

INTEGER*8 XYZ
INTEGER RST
XYZ = INT8(RST)

Here are two ways to “fix” this. First, if this is the only way that you need to convert integers, then a simple assignment is sufficient.

   XYZ = RST

I sometimes add some redundant parentheses when I do these conversions just to remind myself, or some other programmer, that a conversion is being done. XYZ=(RST)

However, if you need to do this conversion within a more complicated expression, then you can define either an external function or you can use a statement function to do the job. Something like this

INTEGER*8 XYZ, INT8
INTEGER RST
INT8(RST) = (RST)
 ...
XYZ = <expression> INT8(RST) <expression>

Most f77 and pre-f77 compilers treated simple statement functions like this as a macro substitution, so there was no actual function call involved, it was all just inline code.

   XYZ = RST

will give XYZ the sign bit of RST and the lowest order 7 bits of RST. If he want XYZ to have the lowest order 8 bits of RST he has to use something else.