Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28456 Discussions

Problem linking when calling C from Fortran in Linux

Lestrade__Michel
Beginner
800 Views

Hi,

I have the following C function with derived types which I want to call from Fortran

typedef struct {
    double x, y, z;
} Vector;

int remove_triangle (Vector *poly, int *polysize, Vector *v1, Vector *v2, Vector *v3);

On the Fortran side, I have this derived type a module called "types"

type,bind(C):: VECTOR
  real(C_DOUBLE) x,y,z
endtype VECTOR

and in another Fortran source file, this interface declaration in the routine that's actually using the C code.

interface
  integer(C_INT) function remove_triangle(poly, polysize, v1, v2, v3) BIND(C,NAME='remove_triangle')    
    use iso_c_binding
    use types
    integer(C_INT) polysize
    type(VECTOR) poly(polysize),v1,v2,v3
  endfunction
endinterface

This links fine under Windows but not under Linux. There, I get this error:

ld: trig_more.o: in function `trig_more_': trig_more.f90:(.text+0x3a1): undefined reference to `remove_triangle'

The C part of the code is built into a static library (.a) and with the nm tool, I can see the decorated name of the function I'm trying to link:

0000000000000060 T _Z15remove_triangleP6VectorPiS0_S0_S0_

while the Fortran object (.o) shows either the undecorated name or the C binding name I provided:

                 U remove_triangle

Both of the objects are on the linker command line and I even made sure that the .a is listed after the .o in the object list. I've tried both directly listing the .a in the list of objects and linking it through the -l flag. I've even tried listing the C .o file directly but get the same error.

So what am I doing wrong and how I can get this to build on both platforms ? The only inconsistency I can see in the declarations is the case sensitivity in the name of the derived type but since it's apparently not possible to use bind(C,NAME=...) on a type declaration and Fortran is case-insensitive, that's not something I seem to have control over...

Compilers used: ifort and icc version 15.0.0 20140723.

0 Kudos
1 Solution
mecej4
Honored Contributor III
800 Views

That the C/C++ compiler created a decorated name for the symbol "remove_triangle" indicates that C++ name decoration took place. You may check that the source file and compiler command are asking for C compilation, not C++ compilation. You may also see if surround the "extern" declaration should be extern "C" {int remove_triangle (Vector *poly, int *polysize, Vector *v1, Vector *v2, Vector *v3);}

View solution in original post

0 Kudos
2 Replies
mecej4
Honored Contributor III
801 Views

That the C/C++ compiler created a decorated name for the symbol "remove_triangle" indicates that C++ name decoration took place. You may check that the source file and compiler command are asking for C compilation, not C++ compilation. You may also see if surround the "extern" declaration should be extern "C" {int remove_triangle (Vector *poly, int *polysize, Vector *v1, Vector *v2, Vector *v3);}

0 Kudos
Lestrade__Michel
Beginner
800 Views

Thanks for the tip; that was indeed the the problem. I wasn't familiar enough with name decoration to recognize this as the output of a C++ compiler.

It turns out that SCONS thinks that files with an uppercase .C extension are C++; renaming it back to lowercase .c forced the file to be compiled and linked as C.

mecej4 wrote:

That the C/C++ compiler created a decorated name for the symbol "remove_triangle" indicates that C++ name decoration took place. You may check that the source file and compiler command are asking for C compilation, not C++ compilation. You may also see if surround the "extern" declaration should be extern "C" {int remove_triangle (Vector *poly, int *polysize, Vector *v1, Vector *v2, Vector *v3);}

0 Kudos
Reply