0

I am writing a short program to test calling the fortran Stripack library from c++. The c++ and fortran files each compile successfully, but errors occur when linking.

The c++ code is as follows:

#include <iostream>
#include <cmath>

#ifdef __cplusplus
extern"C" {
    #endif
    void trmesh_(int&,float[],float[],float[],int[],int[],int[],int&,int[],int[],float[],int&);
    void trlist2_(int&,int[],int[],int[],int&,int[][3],int&);
    #ifdef __cplusplus
}
#endif


int main(){

// Variables for distributing points on sphere.
  int polar = 16;
  int azimuth = 32;
  int n = polar*azimuth-azimuth+2;
  float radius=1.0;

// Define variables needed by Stripack
  float xs[n];
  float ys[n];
  float zs[n];
  int list[6*(n-2)];
  int lptr[6*(n-2)];
  int lend[6*(n-2)];
  int near[n];
  int next[n];
  float dist[n];
  int ltri[2*n-4][3];
  int lnew;
  int ier;
  int nt;

// Distribute n points on surface of unit sphere .
// xs, ys, zs store x, y, and z components pf each point position.
  zs[0] = 1;
  xs[0] = 0;
  ys[0] = 0;
  zs[n] = -1;
  xs[n] = 0;
  ys[n] = 0;
  for (int ii=1; ii<polar; ii++){
    for (int jj=0; jj<azimuth; jj++){
      zs[(ii-1)*azimuth+jj+1] = radius*cos(ii*M_PI/polar);
      xs[(ii-1)*azimuth+jj+1] = radius*sin(ii*M_PI/polar)*sin(jj*2*M_PI/azimuth);
      ys[(ii-1)*azimuth+jj+1] = radius*sin(ii*M_PI/polar)*cos(jj*2*M_PI/azimuth);
    }
  }

// Call stripack subroutines to obtain list of triangles ltri
  trmesh_(n,xs,ys,zs,list,lptr,lend,lnew,near,next,dist,ier);
  trlist2_(n,list,lptr,lend,nt,ltri,ier);

// Output list of triangles
  for (int ii =0; ii<n; ii++){
    std::cout << ltri[ii][0] << " " << ltri[ii][1] << " " << ltri[ii][2] << std::endl;
  }

}

I compile the files as follows:

ifort -c stripack.f90
clang++ -c -O0 -std=c++11 -c -o main.o main.cpp -g
clang++ -o main stripack.o main.o

The first two compilations work fine, but the last one produces the following results. It seems like the subroutines in the fortran file can't find standard fortran functions? I have tried with gfortran and the same problem occurs. Any suggestions as to what is going on would be greatly appreciated.

Undefined symbols for architecture x86_64:
  "___libm_sse2_sincos", referenced from:
      _trplot_ in stripack.o
      _vrplot_ in stripack.o
  "___svml_sincos2", referenced from:
      _trans_ in stripack.o
  "_for_date_and_time", referenced from:
      _timestamp_ in stripack.o
  "_for_stop_core", referenced from:
      _trmesh_ in stripack.o
      _addnod_ in stripack.o
  "_for_trim", referenced from:
      _timestamp_ in stripack.o
  "_for_write_seq_fmt", referenced from:
      _delnod_ in stripack.o
      _edge_ in stripack.o
      _timestamp_ in stripack.o
      _trlprt_ in stripack.o
      _trmesh_ in stripack.o
      _addnod_ in stripack.o
      _trplot_ in stripack.o
      ...
  "_for_write_seq_fmt_xmit", referenced from:
      _delnod_ in stripack.o
      _edge_ in stripack.o
      _timestamp_ in stripack.o
      _trlprt_ in stripack.o
      _trmesh_ in stripack.o
      _addnod_ in stripack.o
      _trplot_ in stripack.o
      ...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
crevell
  • 449
  • 6
  • 19

1 Answers1

1

I will demonstrate this is a link issue by example, you need do a little bit more research to solve the problem, as the information you provide is not complete.

!fortran code, named as x.f90
subroutine testFDLL(str, n) bind(c, name='testFDLL_as_C')
    use ISO_C_BINDING
    integer(c_int), value :: n
    character(kind=c_char), intent(in) :: str(n)
    write(6,*)" Hello FORTRAN : let us do something ...",str
    return
end

The following C code is used for demonstration (you have got C++ mostly right already).

//c named as y.c
#include <stdio.h>
#include <string.h>

int main()
{
    void testFDLL_as_C(char *str, int n);
    char str[] = "Hello from C";
    testFDLL_as_C(str, strlen(str));
    return 0;
}

If you compile and link use the following

ifort -c x.f90
gcc y.c x.o -W -Wall 

Depend on version of ifort and OS, should get error similar as the following

x.o: In function `testFDLL_as_C':
x.f90:(.text+0x42): undefined reference to `for_write_seq_lis'
x.f90:(.text+0x74): undefined reference to `for_write_seq_lis_xmit'
collect2: error: ld returned 1 exit status

You may noticed the undefined reference name pattern is similar with yours, if you link with

gcc y.c x.o -W -Wall -L/path/to/your/ifort_lib -lifcore -ldl

The problem should be solved. Depend on the FORTRAN feature you used, you may need link some more ifort library. This part need you do some research and figure out.

KL-Yang
  • 381
  • 4
  • 8
  • Thank you for this extremely helpful response. I tried to compile the code exactly as you have written it in your answer and saw the errors that you have given upon linking. Unfortunately I have not been able to find a path that works, and my compiler does not recognise the `-lifcore`, `-lifport`, `-lirc`, or `-lsvml` flags. After removing these flags, I have tried `-L/opt/intel/`, `-L/opt/intel/bin/`, `-L/opt/intel/lib/`, and `-L/opt/intel/include/`, none of which worked. Can you suggest what sort of library files I should be looking for? – crevell Mar 27 '19 at 14:28
  • I also found this answer https://stackoverflow.com/questions/5663083/linking-fortran-and-c-binaries-using-gcc but compiling with gfortran and using the -lgfortran flag as suggested here just results in a `library not found for -lgfortran` error. – crevell Mar 27 '19 at 14:30
  • Update: I have managed to get this to compile by running the following commands: `clang++ -c -Wall -std=c++11 main.cpp -o main.o` `gfortran -c stripack.f90 -o stripack.o` `clang++ main.o stripack.o -o main -L/usr/local/lib/gcc/8/ -lgfortran` Unfortunately the program immediately hits a set fault when calling the stripack functions but at least it compiles now. – crevell Mar 27 '19 at 14:58
  • The library path is usually related with installation path of ifort, on linux, usually somewhere around "which ifort", or "locate libifcore.a" kind of thing, it is different from machine to machine and installation to installation. – KL-Yang Mar 27 '19 at 15:09
  • Yes, `which ifort` returned the `/opt/intel/bin` directory, but neither that nor the related directories seemed to be working. But at least I've sorted it with gfortran now - that will suffice. – crevell Mar 27 '19 at 17:59
  • In my system, 'which ifort' gives /opt/intel/compiler-10.1/em64t/bin/ifort, and the lib is in /opt/intel/compiler-10.1/em64t/lib/, my other system has 'which ifort' gives /opt/intel/14.0/bin/ifort, and the library is in /opt/intel/14.0/lib/intel64, anway, you got the point and things work somehow. – KL-Yang Mar 28 '19 at 00:45
  • Unfortunately the directory structure seems to be different on my system and I cannot find a path that works for ifort, but nonetheless it works now with gfortran and your answer was very helpful. – crevell Mar 28 '19 at 14:00