Usage of iso_c_binding

  • Follow


I am trying to get a simple example working to invoke a fortran
subroutine from C++. I have based my simple example off of the example
provided in 14.10 of "fortran 95/2003 explained" by Metcalf, Reid, and
Cohen. Their example C code (I am using C++) was incomplete, so I
created my own example, as best I could, based on what I thought they
were doing. My example .cpp and .f03 files are included at the bottom
of the post. They both compile on Linux (ubuntu), using g++ and
gfortran, respectively, from the command line using:

$ g++ -c invokeF_C.cpp
$ gfortran -c invokeF_F.f03

How do I link the two properly in order to create an executable which
I can run?

I am not very familiar with the command line syntax, so I apologize if
this question seems stupid... but I can't find any examples that use
iso_c_binding that provide not only a simple example, but also the
means to build the solution to run.

I think I need to build the fortran file as a library (.a on Linux,
but how with fortran?) and then link that library with the .cpp. Thus,
I would be building the executable using g++. Would this work?

If anyone could provide me with the necessary command line arguments
that are needed, I would be most thankful... or, if there are any good
examples out there that shed a little more light on a way to properly
use iso_c_binding, with a complete example, that would also help out a
lot.

Thank you.
John N.

I am using:
gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)

invokeF_C.cpp
****************************************
#include <vector>

struct pass{
	int lenc;
	float* c;
};

void simulation( struct pass* arrays );

int main(){
	std::vector< float > cVector(12);
	pass arrays;
	arrays.lenc = cVector.size();
	arrays.c = &cVector[0];
	simulation( &arrays );
}
****************************************

invokeF_F.f03
****************************************
subroutine simulation(arrays) bind(c)
	use iso_c_binding
	type, bind(c) :: pass
		integer (c_int) :: lenc
		type (c_ptr)    :: c
	end type pass
	type (pass), intent(in) :: arrays
	real (c_float), pointer :: c_array(:)

	! associate c_array with an array allocated in C
	call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
end subroutine simulation
****************************************
0
Reply ortp21 (6) 4/9/2010 7:06:05 PM

On 4/9/2010 12:06 PM, John N. wrote:

> invokeF_C.cpp
> ****************************************
> #include<vector>
>
> struct pass{
> 	int lenc;
> 	float* c;
> };
>
> void simulation( struct pass* arrays );
>
> int main(){
> 	std::vector<  float>  cVector(12);
> 	pass arrays;
> 	arrays.lenc = cVector.size();
> 	arrays.c =&cVector[0];
> 	simulation(&arrays );
> }
> ****************************************
>
> invokeF_F.f03
> ****************************************
> subroutine simulation(arrays) bind(c)
> 	use iso_c_binding
> 	type, bind(c) :: pass
> 		integer (c_int) :: lenc
> 		type (c_ptr)    :: c
> 	end type pass
> 	type (pass), intent(in) :: arrays
> 	real (c_float), pointer :: c_array(:)
>
> 	! associate c_array with an array allocated in C
> 	call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
> end subroutine simulation
> ****************************************
You've omitted the extern "C" in your .cpp file.  It's iso_c_binding, 
not _c++_binding, so the linker must see a C function declaration on 
both sides.

-- 
Tim Prince
0
Reply Tim 4/9/2010 7:27:06 PM


On Apr 9, 2:27=A0pm, Tim Prince <tpri...@myrealbox.com> wrote:
> On 4/9/2010 12:06 PM, John N. wrote:
>
>
>
> > invokeF_C.cpp
> > ****************************************
> > #include<vector>
>
> > struct pass{
> > =A0 =A0int lenc;
> > =A0 =A0float* c;
> > };
>
> > void simulation( struct pass* arrays );
>
> > int main(){
> > =A0 =A0std::vector< =A0float> =A0cVector(12);
> > =A0 =A0pass arrays;
> > =A0 =A0arrays.lenc =3D cVector.size();
> > =A0 =A0arrays.c =3D&cVector[0];
> > =A0 =A0simulation(&arrays );
> > }
> > ****************************************
>
> > invokeF_F.f03
> > ****************************************
> > subroutine simulation(arrays) bind(c)
> > =A0 =A0use iso_c_binding
> > =A0 =A0type, bind(c) :: pass
> > =A0 =A0 =A0 =A0 =A0 =A0integer (c_int) :: lenc
> > =A0 =A0 =A0 =A0 =A0 =A0type (c_ptr) =A0 =A0:: c
> > =A0 =A0end type pass
> > =A0 =A0type (pass), intent(in) :: arrays
> > =A0 =A0real (c_float), pointer :: c_array(:)
>
> > =A0 =A0! associate c_array with an array allocated in C
> > =A0 =A0call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
> > end subroutine simulation
> > ****************************************
>
> You've omitted the extern "C" in your .cpp file. =A0It's iso_c_binding,
> not _c++_binding, so the linker must see a C function declaration on
> both sides.
>
> --
> Tim Prince

Tim,

Ah, I forgot that when writing my example. Thanks for the fast
response.

Do you have any tips for the best way to build the fortran code as a
library and link that with the c++ code? I still can't get any of the
command line commands I try to work properly...

John N.

invokeF_C.cpp
****************************************
#include<vector>

struct pass{
    int lenc;
    float* c;
};

extern "C" void simulation( struct pass* arrays );

int main(){
   std::vector<  float>  cVector(12);
    pass arrays;
    arrays.lenc =3D cVector.size();
    arrays.c =3D&cVector[0];
    simulation(&arrays );
}
****************************************
0
Reply John 4/9/2010 7:57:50 PM

On Apr 9, 2:57=A0pm, "John N." <ort...@gmail.com> wrote:
> On Apr 9, 2:27=A0pm, Tim Prince <tpri...@myrealbox.com> wrote:
>
>
>
> > On 4/9/2010 12:06 PM, John N. wrote:
>
> > > invokeF_C.cpp
> > > ****************************************
> > > #include<vector>
>
> > > struct pass{
> > > =A0 =A0int lenc;
> > > =A0 =A0float* c;
> > > };
>
> > > void simulation( struct pass* arrays );
>
> > > int main(){
> > > =A0 =A0std::vector< =A0float> =A0cVector(12);
> > > =A0 =A0pass arrays;
> > > =A0 =A0arrays.lenc =3D cVector.size();
> > > =A0 =A0arrays.c =3D&cVector[0];
> > > =A0 =A0simulation(&arrays );
> > > }
> > > ****************************************
>
> > > invokeF_F.f03
> > > ****************************************
> > > subroutine simulation(arrays) bind(c)
> > > =A0 =A0use iso_c_binding
> > > =A0 =A0type, bind(c) :: pass
> > > =A0 =A0 =A0 =A0 =A0 =A0integer (c_int) :: lenc
> > > =A0 =A0 =A0 =A0 =A0 =A0type (c_ptr) =A0 =A0:: c
> > > =A0 =A0end type pass
> > > =A0 =A0type (pass), intent(in) :: arrays
> > > =A0 =A0real (c_float), pointer :: c_array(:)
>
> > > =A0 =A0! associate c_array with an array allocated in C
> > > =A0 =A0call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
> > > end subroutine simulation
> > > ****************************************
>
> > You've omitted the extern "C" in your .cpp file. =A0It's iso_c_binding,
> > not _c++_binding, so the linker must see a C function declaration on
> > both sides.
>
> > --
> > Tim Prince
>
> Tim,
>
> Ah, I forgot that when writing my example. Thanks for the fast
> response.
>
> Do you have any tips for the best way to build the fortran code as a
> library and link that with the c++ code? I still can't get any of the
> command line commands I try to work properly...
>
> John N.
>
> invokeF_C.cpp
> ****************************************
> #include<vector>
>
> struct pass{
> =A0 =A0 int lenc;
> =A0 =A0 float* c;
>
> };
>
> extern "C" void simulation( struct pass* arrays );
>
> int main(){
> =A0 =A0std::vector< =A0float> =A0cVector(12);
> =A0 =A0 pass arrays;
> =A0 =A0 arrays.lenc =3D cVector.size();
> =A0 =A0 arrays.c =3D&cVector[0];
> =A0 =A0 simulation(&arrays );}
>
> ****************************************

This may be very wrong, but this is one of the things I was trying to
do:

$ g++ -c invokeF_C.cpp
$ gfortran -c invokeF_F.f03
$ g++ -o test invokeF_C.o invokeF_F.o

Which returns:

invokeF_F.o: In function `simulation':
invokeF_F.f03:(.text+0xad): undefined reference to
`__iso_c_binding_c_f_pointer_r4'

Do I need some other flags passed to g++ to tell it that I am using a
fortran created object file? Can I build the fortran file as a
library? Am I just missing some big step?

If you can't tell by now, I am not very familiar with these things,
unfortunately.

John N.
0
Reply John 4/9/2010 8:07:42 PM

On 2010-04-09 17:07:42 -0300, "John N." <ortp21@gmail.com> said:

> On Apr 9, 2:57�pm, "John N." <ort...@gmail.com> wrote:
>> On Apr 9, 2:27�pm, Tim Prince <tpri...@myrealbox.com> wrote:
>> 
>> 
>> 
>>> On 4/9/2010 12:06 PM, John N. wrote:
>> 
>>>> invokeF_C.cpp
>>>> ****************************************
>>>> #include<vector>
>> 
>>>> struct pass{
>>>> � �int lenc;
>>>> � �float* c;
>>>> };
>> 
>>>> void simulation( struct pass* arrays );
>> 
>>>> int main(){
>>>> � �std::vector< �float> �cVector(12);
>>>> � �pass arrays;
>>>> � �arrays.lenc = cVector.size();
>>>> � �arrays.c =&cVector[0];
>>>> � �simulation(&arrays );
>>>> }
>>>> ****************************************
>> 
>>>> invokeF_F.f03
>>>> ****************************************
>>>> subroutine simulation(arrays) bind(c)
>>>> � �use iso_c_binding
>>>> � �type, bind(c) :: pass
>>>> � � � � � �integer (c_int) :: lenc
>>>> � � � � � �type (c_ptr) � �:: c
>>>> � �end type pass
>>>> � �type (pass), intent(in) :: arrays
>>>> � �real (c_float), pointer :: c_array(:)
>> 
>>>> � �! associate c_array with an array allocated in C
>>>> � �call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
>>>> end subroutine simulation
>>>> ****************************************
>> 
>>> You've omitted the extern "C" in your .cpp file. �It's iso_c_binding,
>>> not _c++_binding, so the linker must see a C function declaration on
>>> both sides.
>> 
>>> --
>>> Tim Prince
>> 
>> Tim,
>> 
>> Ah, I forgot that when writing my example. Thanks for the fast
>> response.
>> 
>> Do you have any tips for the best way to build the fortran code as a
>> library and link that with the c++ code? I still can't get any of the
>> command line commands I try to work properly...
>> 
>> John N.
>> 
>> invokeF_C.cpp
>> ****************************************
>> #include<vector>
>> 
>> struct pass{
>> � � int lenc;
>> � � float* c;
>> 
>> };
>> 
>> extern "C" void simulation( struct pass* arrays );
>> 
>> int main(){
>> � �std::vector< �float> �cVector(12);
>> � � pass arrays;
>> � � arrays.lenc = cVector.size();
>> � � arrays.c =&cVector[0];
>> � � simulation(&arrays );}
>> 
>> ****************************************
> 
> This may be very wrong, but this is one of the things I was trying to
> do:
> 
> $ g++ -c invokeF_C.cpp
> $ gfortran -c invokeF_F.f03
> $ g++ -o test invokeF_C.o invokeF_F.o

"test" is a bad name of a Unix executable as it will conflict with one of
the heavily use shell commands. Try something like "F95_with_C_Test" which
is more in the spirit of your other names.

When you have "test" problems it can be very mysterious!

> Which returns:
> 
> invokeF_F.o: In function `simulation':
> invokeF_F.f03:(.text+0xad): undefined reference to
> `__iso_c_binding_c_f_pointer_r4'
> 
> Do I need some other flags passed to g++ to tell it that I am using a
> fortran created object file? Can I build the fortran file as a
> library? Am I just missing some big step?
> 
> If you can't tell by now, I am not very familiar with these things,
> unfortunately.
> 
> John N.


0
Reply Gordon 4/9/2010 8:20:01 PM

On Apr 9, 3:20=A0pm, Gordon Sande <Gordon.Sa...@EastLink.ca> wrote:
> On 2010-04-09 17:07:42 -0300, "John N." <ort...@gmail.com> said:
>
>
>
> > On Apr 9, 2:57=A0pm, "John N." <ort...@gmail.com> wrote:
> >> On Apr 9, 2:27=A0pm, Tim Prince <tpri...@myrealbox.com> wrote:
>
> >>> On 4/9/2010 12:06 PM, John N. wrote:
>
> >>>> invokeF_C.cpp
> >>>> ****************************************
> >>>> #include<vector>
>
> >>>> struct pass{
> >>>> =A0 =A0int lenc;
> >>>> =A0 =A0float* c;
> >>>> };
>
> >>>> void simulation( struct pass* arrays );
>
> >>>> int main(){
> >>>> =A0 =A0std::vector< =A0float> =A0cVector(12);
> >>>> =A0 =A0pass arrays;
> >>>> =A0 =A0arrays.lenc =3D cVector.size();
> >>>> =A0 =A0arrays.c =3D&cVector[0];
> >>>> =A0 =A0simulation(&arrays );
> >>>> }
> >>>> ****************************************
>
> >>>> invokeF_F.f03
> >>>> ****************************************
> >>>> subroutine simulation(arrays) bind(c)
> >>>> =A0 =A0use iso_c_binding
> >>>> =A0 =A0type, bind(c) :: pass
> >>>> =A0 =A0 =A0 =A0 =A0 =A0integer (c_int) :: lenc
> >>>> =A0 =A0 =A0 =A0 =A0 =A0type (c_ptr) =A0 =A0:: c
> >>>> =A0 =A0end type pass
> >>>> =A0 =A0type (pass), intent(in) :: arrays
> >>>> =A0 =A0real (c_float), pointer :: c_array(:)
>
> >>>> =A0 =A0! associate c_array with an array allocated in C
> >>>> =A0 =A0call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
> >>>> end subroutine simulation
> >>>> ****************************************
>
> >>> You've omitted the extern "C" in your .cpp file. =A0It's iso_c_bindin=
g,
> >>> not _c++_binding, so the linker must see a C function declaration on
> >>> both sides.
>
> >>> --
> >>> Tim Prince
>
> >> Tim,
>
> >> Ah, I forgot that when writing my example. Thanks for the fast
> >> response.
>
> >> Do you have any tips for the best way to build the fortran code as a
> >> library and link that with the c++ code? I still can't get any of the
> >> command line commands I try to work properly...
>
> >> John N.
>
> >> invokeF_C.cpp
> >> ****************************************
> >> #include<vector>
>
> >> struct pass{
> >> =A0 =A0 int lenc;
> >> =A0 =A0 float* c;
>
> >> };
>
> >> extern "C" void simulation( struct pass* arrays );
>
> >> int main(){
> >> =A0 =A0std::vector< =A0float> =A0cVector(12);
> >> =A0 =A0 pass arrays;
> >> =A0 =A0 arrays.lenc =3D cVector.size();
> >> =A0 =A0 arrays.c =3D&cVector[0];
> >> =A0 =A0 simulation(&arrays );}
>
> >> ****************************************
>
> > This may be very wrong, but this is one of the things I was trying to
> > do:
>
> > $ g++ -c invokeF_C.cpp
> > $ gfortran -c invokeF_F.f03
> > $ g++ -o test invokeF_C.o invokeF_F.o
>
> "test" is a bad name of a Unix executable as it will conflict with one of
> the heavily use shell commands. Try something like "F95_with_C_Test" whic=
h
> is more in the spirit of your other names.
>
> When you have "test" problems it can be very mysterious!
>
> > Which returns:
>
> > invokeF_F.o: In function `simulation':
> > invokeF_F.f03:(.text+0xad): undefined reference to
> > `__iso_c_binding_c_f_pointer_r4'
>
> > Do I need some other flags passed to g++ to tell it that I am using a
> > fortran created object file? Can I build the fortran file as a
> > library? Am I just missing some big step?
>
> > If you can't tell by now, I am not very familiar with these things,
> > unfortunately.
>
> > John N.
>
>

Oops, I did not realize that might pose problems! I updated the name
of the executable. I get the same error:

$ g++ -c invokeF_C.cpp
$ gfortran -c invokeF_F.f03
$ g++ -o Invoke_F_with_C_Test invokeF_C.o invokeF_F.o

Produces:

invokeF_F.o: In function `simulation':
invokeF_F.f03:(.text+0xad): undefined reference to
`__iso_c_binding_c_f_pointer_r4'
collect2: ld returned 1 exit status

John N.
0
Reply John 4/9/2010 8:28:10 PM

John N. wrote:
> 
> This may be very wrong, but this is one of the things I was trying to
> do:
> 
> $ g++ -c invokeF_C.cpp
> $ gfortran -c invokeF_F.f03
> $ g++ -o test invokeF_C.o invokeF_F.o
> 
> Which returns:
> 
> invokeF_F.o: In function `simulation':
> invokeF_F.f03:(.text+0xad): undefined reference to
> `__iso_c_binding_c_f_pointer_r4'
> 
> Do I need some other flags passed to g++ to tell it that I am using a
> fortran created object file? Can I build the fortran file as a
> library? Am I just missing some big step?
> 
> If you can't tell by now, I am not very familiar with these things,
> unfortunately.

I think if you use g++ as the driver, you may need to link against 
libgfortran.
0
Reply Craig 4/9/2010 9:36:14 PM

On Apr 9, 4:36=A0pm, Craig Powers <craig.pow...@invalid.invalid> wrote:
> John N. wrote:
>
> > This may be very wrong, but this is one of the things I was trying to
> > do:
>
> > $ g++ -c invokeF_C.cpp
> > $ gfortran -c invokeF_F.f03
> > $ g++ -o test invokeF_C.o invokeF_F.o
>
> > Which returns:
>
> > invokeF_F.o: In function `simulation':
> > invokeF_F.f03:(.text+0xad): undefined reference to
> > `__iso_c_binding_c_f_pointer_r4'
>
> > Do I need some other flags passed to g++ to tell it that I am using a
> > fortran created object file? Can I build the fortran file as a
> > library? Am I just missing some big step?
>
> > If you can't tell by now, I am not very familiar with these things,
> > unfortunately.
>
> I think if you use g++ as the driver, you may need to link against
> libgfortran.

Craig,

Thank you! That did it. I updated the example to add a little write
statement inside, just to make sure it was working properly.

I ended up using the following command line commands to get it
working:

$ g++ -c invokeF_C.cpp
$ gfortran -c invokeF_F.f03
$ g++ -o Invoke_F_with_C_Test invokeF_C.o invokeF_F.o -L /usr/lib -
lgfortran
$ ./Invoke_F_with_C_Test

Results in the following, using the updated files below:

> in here.

Thank you guys for the help.

John N.

invokeF_C.cpp
****************************************
#include <vector>

struct pass{
        int lenc;
        float* c;

};

extern "C" void simulation( struct pass* arrays );

int main(){
        std::vector< float > cVector(12);
        pass arrays;
        arrays.lenc =3D cVector.size();
        arrays.c =3D &cVector[0];
        simulation( &arrays );
}

****************************************

invokeF_F.f03
****************************************
subroutine simulation(arrays) bind(c)
        use iso_c_binding
        type, bind(c) :: pass
                integer (c_int) :: lenc
                type (c_ptr)    :: c
        end type pass
        type (pass), intent(in) :: arrays
        real (c_float), pointer :: c_array(:)

        ! associate c_array with an array allocated in C
        call c_f_pointer( arrays%c, c_array, (/arrays%lenc/) )
        write(*,*) "in here."
end subroutine simulation
****************************************
0
Reply John 4/9/2010 11:02:00 PM

Clarifying what others have posted, the driver for language A needs to 
be told to pull in the libraries for language B.

Perhaps:

gfortran -c invokeF_F.f03
g++ -c invokeF_C.cpp
g++ invokeF_C.o invokeF_F.o -lgfortran -o my_program_name

With this toolset, you could also compile and link all at the same time, 
here using the gcc driver and specifying both c++ and fortran libraries 
explicitly:

gcc invokeF_C.cpp invokeF_F.f03 -lstdc++ -lgfortran -o my_program_name

For more information on what a particular language driver does for you 
behind the scenes can be observed by adding -v to the command line for 
the driver.

Creating a library (collection of object files) as an intermediate step 
may be appropriate when you have a larger number of source code files 
and you want to simplify the specification of all the object files in 
the linking step.  It is not a requirement.

IanH
0
Reply Ian 4/9/2010 11:24:25 PM

John N. <ortp21@gmail.com> wrote:
(snip)
 
> $ g++ -c invokeF_C.cpp
> $ gfortran -c invokeF_F.f03
> $ g++ -o Invoke_F_with_C_Test invokeF_C.o invokeF_F.o

A better choice is to use gfortran for the link command.
gfortran should bring in the Fortran libraries.  There is a good
chance that those also use the C libraries, where the other way
around is less likely.

If the Fortran library uses the C library for I/O, it might
be possible to do I/O from both Fortran and C.  (Even so,
if both are buffering things might not come out in the expected order.)

-- glen

0
Reply glen 4/10/2010 1:23:06 AM

9 Replies
599 Views

(page loaded in 0.154 seconds)

Similiar Articles:













7/24/2012 6:10:43 AM


Reply: