I'm trying to modify this code (gist as back up) to become gfortran-gcc compatible.
[VALUE]
tagsPOINTER
with -fcray-pointer
flag for gfortran, instead of the [REFERENCE]
tag__stdcall
, because tried the #define __stdcall __attribute__((stdcall))
which caused warning: ‘stdcall’ attribute ignored [-Wattributes]
now this is what I have:C code CMAIN.C
:
#include <stdio.h>
extern int FACT_(int n);
extern void PYTHAGORAS_(float a, float b, float *c);
main()
{
float c;
printf("Factorial of 7 is: %d\n", FACT_(7));
PYTHAGORAS_(30, 40, &c);
printf("Hypotenuse if sides 30, 40 is: %f\n", c);
}
the FORTRAN code FORSUBS.FOR
:
INTEGER*4 FUNCTION Fact (n)
INTEGER*4 n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, cp)
REAL*4 a
REAL*4 b
POINTER (cp, c)
REAL*4 c
c = SQRT (a * a + b * b)
END
the Makefile
:
all:
gfortran -c FORSUBS.FOR -fcray-pointer
gcc -c CMAIN.C
gfortran -o result.out FORSUBS.o CMAIN.o
rm -rf *.o
clean :
rm -rf *.out *~ *.bak *.o
However I still get the error:
CMAIN.o: In function `main':
CMAIN.C:(.text+0x1d): undefined reference to `FACT_(int)'
CMAIN.C:(.text+0x4c): undefined reference to `PYTHAGORAS_(float, float, float*)'
I would appreciate if you could help me know:
P.S.1. also shared on Reddit. P.S.2. operating system and compiler specifications are same as this question.
In addition to my top comments, Fortran passes by reference, so you have to modify the .c
and the .for
files.
The code below works. There may be a simpler way to declare things, but this should [at least] get you further along. Caveat: I haven't done much fortran since Fortran IV days, so I'm a bit rusty. I'd defer to Vladimir's VALUE
solution as a better way to go.
#include <stdio.h>
#if 0
extern int fact_(int n);
extern void pythagoras_(float a, float b, float *c);
#else
extern int fact_(int *n);
extern void pythagoras_(float *a, float *b, float *c);
#endif
int
main(void)
{
float c;
#if 0
printf("Factorial of 7 is: %d\n", fact_(7));
#else
int n = 7;
printf("Factorial of 7 is: %d\n", fact_(&n));
#endif
#if 0
pythagoras_(30, 40, &c);
#else
float a = 30;
float b = 40;
pythagoras_(&a, &b, &c);
#endif
printf("Hypotenuse if sides 30, 40 is: %f\n", c);
return 0;
}
INTEGER*4 FUNCTION Fact (n)
INTEGER*4 n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, c)
REAL*4 a
REAL*4 b
REAL*4 c
c = SQRT (a * a + b * b)
END
Here is the program output:
Factorial of 7 is: 5040
Hypotenuse if sides 30, 40 is: 50.000000
UPDATE:
I get the same
undefined reference
error from your code!
Aha!
One thing I didn't mention [because I didn't think it would make a difference] is that I changed the source file names to use all lowercase letters (e.g. CMAIN.C --> cmain.c
and FORSUBS.FOR --> forsubs.for
)
With that, the output of nm *.o
produces:
cmain.o:
U fact_
0000000000000000 T main
U printf
U pythagoras_
forsubs.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
The change in the fortran source filename doesn't matter too much. But, the C source filename does!
More to the point it's the filename suffix (i.e. .C
changed to .c
).
This is because gcc
will [try to be smart and] look at the suffix to determine which language the file is written in and compile accordingly. For example, gcc -c foo.cpp
will compile the file as if it is written in c++
and not c
, just as if the command were: g++ -c foo.cpp
Although .cpp
is the [more] usual suffix for a c++
filename, an alternate suffix for c++
files is: .C
That is, most projects use the .cpp
convention, but some use the .C
convention. One of the reasons for preferring .cpp
over .C
is that Windows filesystems are case insensitive. So, .C
and .c
would appear the same. However, POSIX systems (e.g. linux, macOSX, iOS, android, etc.) have case sensitive filenames so either convention can be used.
So, gcc -c CMAIN.C
will compile as c++
. This does c++
style "name mangling" of symbols--not what we want. In c++
, the mangling is done to allow "overloading" of function names. That is, two [or more] different functions can have the same name, as long as they use different arguments. For example:
void calc(int val);
void calc(int val1,int val2);
void calc(double fval);
Here is the output of nm *.o
if we use CMAIN.C
:
CMAIN.o:
0000000000000000 T main
U printf
U _Z11pythagoras_PfS_S_
U _Z5fact_Pi
FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
Running that file through c++filt
to "demangle" the c++
names we get:
CMAIN.o:
0000000000000000 T main
U printf
U pythagoras_(float*, float*, float*)
U fact_(int*)
FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
So, try to use lowercase filenames if possible [that is recommended best practice]. But, at a minimum, don't use .C