Calling fortran function from C

Hi,

I need to call a fortran function from C, I have created a fortran.o file for the object call.

I defined the fortran function in C as extern double function();

I use a makefile to compile a bunch of files stored in various directories.
This makefile creates .o files for individual files in their directories and then updates a .a file.

Let’s say my fortran file is in Xyz directory. This directory has xyz.c, xyz1.c and fortran.o files.

Is there a way I can create the fortran.o file and link to the .c file and then update the .a file?

Thank you

Btw: I think page 248 in the users manual has a typo. it should be $ pgcc -c cmain.c instead of cmain.f

Hi,

Is this fortran file will be a part of library? If so, you can add it to your make file. It should update .a file automatically. When you link this library to your program, if C is a main program, you may need to link with either -pgf77libs or -pgf90libs (depends on which compiler you use).

For more info on how to set up to archive library in makefile on linux type:
prompt% info make
and look for Using ‘make’ to Update Archive Files section.

Thank you for your input on the user manual.
Hongyon

Hi,

So, I tried doing what you suggested (I think)
My make file calls the following make_all file in the directory. This make_all file updates the archive file with the files in the directory

SHELL=/bin/sh

.SUFFIXES: .o .c .f .F

include …/machines/make.$(BOX)

INCD= …/include
INC= …/CASM


INCLUDE= $(INCD)/define.h $(INCD)/macro.h $(INCD)/share_extern.h
$(INCD)/fnctn.h $(INCD)/share_declare.h
$(INC)/csm_defs.h $(INC)/fortran.h
LB= …/lib/libadh.a

LOBJ=$(LB)(CAM.o) $(LB)(Casm_wrap.o) $(LB)(casm.o)

all: $(LB)

$(LB): $(LOBJ) $(INCLUDE)
@echo $(LB) updated.

$(LOBJ): $(INCLUDE)


.c.a : $(INCLUDE)
$(CC) $(CFLAGS) $(PFLAGS) -I$(INCD) -c $<
$(ARCH) $(ARCHFLAGS) $@ $.o
-rm -f $
.o



clean:
-rm -f $(LB)

Ignore the fortran.h in the include list.

The casm.o file is the fortran objects that I created using pgf90 -c casm.f

In the C file Casm_wrap.c I define the fortran function extern double casm_()
.

However, when I make the program it returns an error saying that ccasm undefined function in CASM_wrap

Any further help will be appreciated.

Thanks

Is it on win32, win64, or linux? What C compiler do you use to compile your C codes? I ask because there might be some naming or calling convention issue.

Below is an example for linux:
% pgf90 -c f.f
% pgcc main.c f.o -pgf90libs

main.c:

#define ccsm ccsm_
extern double ccsm_();
void CASM_wrap () {
double a;
a=ccsm();
}
main () {
CASM_wrap();
}


f.f:
double precision function ccsm()
end


Hongyon

It’s on win32.

Thanks

Btw, if I have the following defined:

typedef struct {
float **adh;
float **grad;
} NODAL;

NODAL *nodes;

nodes_.adh[y] = random_var[j][k];

Is there a protocol for transferring this to Fortran??

Thanks
GSavant

ERDC, USACE_

Hi GSavant,

What is it you are trying to do with adh and grad? As you know, the data layout in Fortran and C are not the same(column-wise vs. row-wise). It may not work if you try to do some fancy references. Please look at our PGI Fortran Language Reference for more information.

Below is a simple program for win32.
PGI$ cat a.c


struct blockme {
int n;
float f;
double d;
}
#define printme PRINTME

extern void __stdcall PRINTME();
struct blockme a;

main () {
a.n=7;
a.f=2.3;
a.d=1.901;
printme();
}
PGI$ cat f.f
subroutine printme()
!DEC$ ATTRIBUTES ALIAS:‘_a’::a
common /a/n,f,d
integer n
real4 f
real
8 d
print *, n,f,d
end


Hongyon

Thanks for the reply and the sample code.

I’ve tried compiling the code with -Munix and without it ( to try your previous suggestion for UNix and this last one for win32).

However, without -Munix: _stdcall gives and error saying “illegal use of _stdcall”

With -Munix: I still get unresolved external.

With -MUNIX:

{

#define casm casm_

extern double casm_(double *, float ** , float ** , float *, float *, float *, float *, float *,
float *, float *, float * , float *,float *, float * , float *, float *,
float *, float *, float *, double *, double *);
}

Without -Munix:
#define casm CASM
extern double _stdcall CASM(same vars as above)

Is there something I am doing obviously wrong here?

I took out the structures from my code, I figured the effort in doing that wasn’t worth the payoff.

thanks
GSavant

Never mind…

Ok, so the compile works and messages are passed to Fortran. However, when I try to pass 2 D arrays fortran does not get the values. Are 2D arrays passed differently from 1D arrays?

In C I have the arrays defined as float **bp and in fortran they are
dimension bp(4,10)

and the fortran subroutine is
double precision function casm( ) various vars inside the brackets

Thanks
GSavant

Hi GSavant,

What is it you are trying to do in Fortran routine with float**? As you know, the data layout in Fortran and C are not the same(column-wise vs. row-wise). It may not work if you try to do references.

Hongyon

Hongyon,

Thanks for all your help, I have linked my forrtan and C codes and they are performing as expected.

I have a question though, how do I clear the static variable declared in Fortran from memory? The reason this is important is b/c the fortran code is called almost a million times sometimes greater and the memory gobbled up becomes immense.

Or,

Is there a way I can tell the fortran code to declare the variables only once and not declare them everytime the code is called.

Thanks

Hi,

I am not quite sure why calling a million times would cause the memory gobbled up, unless it is called recursively.

You can use SAVE statement for local variables or common block for global variables.

Hongyon