C++/Fortran mixed programming: undefined reference to `_gfortran_reshape_r8'

夙愿已清 提交于 2019-12-08 04:20:17

问题


I am compiling a C++ code together with Fortran subroutine. The C++ cpp code is like:

#include "Calculate.h"
extern "C" double SolveEq_(double *Gvalue, double *GvalueU, double *GvalueV, double *Gnodex, double *Gnodey, double *GtimeInc, double *Glfs);

template <class T1, class T2>
void Calculate(vector<Element<T1, T2> > &elm, GParameter &GeqPm, GmeshInfo &Gmesh)
{
    // Solving Equation using Fortran code
    SolveEq_(&Gmesh.Gvalue[0], &Gmesh.GvalueU[0], &Gmesh.GvalueV[0], &Gmesh.Gnodex[0], &Gmesh.Gnodey[0], &GeqPm.GtimeInc, &GeqPm.Glfs);
    return;
}

And the Fortran code is like:

!==========================================================================
Module Inputpar
Implicit None
Integer,parameter :: Numx = 200, Numy = 200
End Module
!======================================== PROGRAM =============================================
Subroutine SolveEq(Gvalue, GvalueU, GvalueV, Gnodex, Gnodey, Deltat, Lfs);
Use Inputpar
Implicit None

Real*8 Deltat, Lfs, Dt, Su
Real*8 Gvalue(1, (Numx+1)*(Numy+1)), GvalueU(1, (Numx+1)*(Numy+1)), GvalueV(1, (Numx+1)*(Numy+1))
Real*8 Gnodex(0:Numx), Gnodey(0:Numy)

Real*8 DX, DY
Real*8 X(-3:Numx+3), Y(-3:Numy+3)
Real*8 VelX(-3:Numx+3,-3:Numy+3), VelY(-3:Numx+3,-3:Numy+3)
Real*8 G(-3:Numx+3,-3:Numy+3)

Common /CommonData/ X, Y, DX, DY, VelX, VelY, G, Dt, Su

!============================= Data Transfer ============================
Dt                  = Deltat
Su                  = Lfs
X          (0:Numx) = Gnodex(0:Numx)
Y          (0:Numy) = Gnodey(0:Numy)
VelX(0:Numx,0:Numy) = transpose(reshape(GvalueU,(/Numy+1,Numx+1/)))
VelY(0:Numx,0:Numy) = transpose(reshape(GvalueV,(/Numy+1,Numx+1/)))
G   (0:Numx,0:Numy) = transpose(reshape(Gvalue ,(/Numy+1,Numx+1/)))

!==========Some other lines neglected here=================

End
!======================================== END PROGRAM =========================================

Firstly compile the Fortran code using command:

      gfortran SolveEq.f90 -c -o SolveEq.o

And then compile the C++/Fortran codes together using makefile:

# Compiler
CC = g++

# Debug option
DEBUG = false

# Source directory of codes
SRC1 = /home
SRC2 = $(SRC1)/Resources
SRC3 = $(SRC1)/Resources/Classes

OPT=-fopenmp -O2

ifdef $(DEBUG)
  PROG=test.out
else
  PROG=i.out
endif

# Linker
#LNK=-I$(MPI)/include -L$(MPI)/lib -lmpich -lopa -lmpl -lpthread

OBJS = libtseutil.a Calculate.o SolveEq.o

OBJS_F=$(OBJS)
SUF_OPTS1=$(OBJS_F)
SUF_OPTS2=-I$(SRC2)/
SUF_OPTS3=-I$(SRC3)/
SUF_OPTS4=

# Details of compiling
$(PROG): $(OBJS_F)
    $(CC) $(OPT) -o $@ $(SUF_OPTS1)
%.o: $(SRC1)/%.cpp
    $(CC) $(OPT) -c $< $(SUF_OPTS2)
%.o: $(SRC2)/%.cpp
    $(CC) $(OPT) -c $< $(SUF_OPTS3)
%.o: $(SRC3)/%.cpp
    $(CC) $(OPT) -c $< $(SUF_OPTS4)

# Clean
.PHONY: clean
clean:
    @rm -rf *.o *.oo *.log

However, the error shows that:

g++ -fopenmp -O2 -o libtseutil.a Calculate.o SolveEq.o
Calculate.o: In function `void Calculate<CE_Tri, SolElm2d>(std::vector<Element<CE_Tri, SolElm2d>, std::allocator<Element<CE_Tri, SolElm2d> > >&, GParameter&, GmeshInfo&)':
Calculate.cpp:(.text._Z10CalculateGI6CE_Tri8SolElm2dEvRSt6vectorI7ElementIT_T0_ESaIS6_EER10GParameterR9GmeshInfo[_Z10CalculateGI6CE_Tri8SolElm2dEvRSt6vectorI7ElementIT_T0_ESaIS6_EER10GParameterR9GmeshInfo]+0x3c): undefined reference to `SolveEq_'
SolveEq.o: In function `solveeq_':
SolveEq.f90:(.text+0x2b8e): undefined reference to `_gfortran_reshape_r8'
SolveEq.f90:(.text+0x2d2a): undefined reference to `_gfortran_reshape_r8'
SolveEq.f90:(.text+0x2ec6): undefined reference to `_gfortran_reshape_r8'
SolveEq.f90:(.text+0x31fa): undefined reference to `_gfortran_reshape_r8'
collect2: error: ld returned 1 exit status

How does this happen?

I used a simple case to test the mixed compiling. The C++ code was:

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;

extern "C" double fortran_sum_(double *sum, double *su2m, double *vec, double* vec2, int *size);

int main(int argc, char ** argv)
{
    int size;
    double sum, sum2;
    double aa,bb,cc,dd;
    vector<double> vec;
    vector<double> vec2;

    size=2;
    aa=1.0;
    bb=2.0;
    sum=0.0;
    sum2=0.0;

    vec.push_back(aa);
    vec.push_back(bb);
    vec2.push_back(aa*2.0);
    vec2.push_back(bb*2.0);

    fortran_sum_(&sum, &sum2, &vec[0], &vec2[0], &size);

    cout << "Calling a Fortran function" << endl;
    cout << "============================" << endl;
    cout << "size = " << size << endl;
    cout << "sum = " << sum << endl;
    cout << "sum2 = " << sum2 << endl << endl;
}

And the Fortran code was:

Subroutine fortran_sum(gsum, gsum2, gvec, gvec2, gsize2)
  integer gsize,gsize2
  real*8 gvec(0:gsize2-1), gvec2(0:1)
  real*8 gsum, gsum2
  gsum = gvec(0)+gvec(1);
  gsum2 = gvec2(0)+gvec2(1);
  gsize = gsize*2;
end 

Then used commands to compile :

gfortran fortran_sum.f90 -c -o fortran_sum.o
g++ fortran_sum.o call_fortran.cpp -o a.out
./a.out

It worked well:

Calling a Fortran function
============================
size = 2
sum = 3
sum2 = 6

回答1:


The function _gfortran_reshape_r8 is part of the library that is used by code compiled by gfortran. When you compile in a single language such libraries are automatically linked because whichever program you use to do the linking knows about them. When you link mixed code, you need to find and explicitly put on the command line the libraries for the language that doesn't correspond to the linker you've chosen. Usually you link with the C++ syntax, as you've done here, and add the fortran compiler's libraries explicitly.




回答2:


I am little bit weak on Fortran language. When I compiled your fortran code and put it through nm, it gave me the following. There is no symbol "SolveEq_". There is just "solveeq_".

0000000000000020 r A.15.3480
0000000000000000 r A.3.3436
0000000000000010 r A.9.3463
                 U _gfortran_reshape_r8
00000000000fbe28 C commondata_
                 U free
                 U malloc
0000000000000000 T solveeq_

Edit: It compiled for me when I used "solveeq_". Here is simplified code for demo (main.cpp):

extern "C" double solveeq_(
              double *Gvalue, double *GvalueU, 
              double *GvalueV, double *Gnodex, 
              double *Gnodey, double *GtimeInc, double *Glfs
           );

template <typename T>
void Calculate(T *one, T *two, T *three,
               T *four, T *five, T *six, T *seven) {
    solveeq_(one,two,three,four,five,six,seven);
}

int main(int argc, char ** argv) {
     double one,two,three,four,five,six,seven;
     Calculate<double>(&one,&two,&three,&four,&five,&six,&seven);
}

Compiled it as (f.f90 has the fortran code):

gfortran -c f.f90
g++ f.o main.cpp -lgfortran

It seems, since 2003, if you want to call a fortran function from C/C++, you could use BIND (It may not with fortran/fortran though without some more additional effort).

Subroutine SolveEq(F) BIND(C,NAME="SolveMyEquation")
Real Gvalue, GvalueU, GvalueV, Gnodex, Gnodey, Deltat, Lfs
End



回答3:


Thanks to every one, especially @Brick and @blackpen. The problem has been fixed.

1), Add -lgfortran into command line so that the function,otherwise it will show: undefined reference to `_gfortran_reshape_r8'.

2), Change the name of the .f90 function into small letters "solveeq" other wise it will show: undefined reference to `SolveGeq_'

So finally my .cpp is changed into :

#include "Calculate.h"
extern "C" void solveeq_(double *Gvalue, double *GvalueU, double *GvalueV, double *Gnodex, double *Gnodey, double *GtimeInc, double *Glfs);

template <class T1, class T2>
void Calculate(vector<Element<T1, T2> > &elm, GParameter &GeqPm, GmeshInfo &Gmesh)
{
    // Solving Equation using Fortran code
    solveeq_(&Gmesh.Gvalue[0], &Gmesh.GvalueU[0], &Gmesh.GvalueV[0], &Gmesh.Gnodex[0], &Gmesh.Gnodey[0], &GeqPm.GtimeInc, &GeqPm.Glfs);
    return;
}

The fortran code .f90 is like:

!==========================================================================
Module Inputpar
Implicit None
Integer,parameter :: Numx = 200, Numy = 200
End Module
!======================================== PROGRAM =============================================
Subroutine SolveEq(Gvalue, GvalueU, GvalueV, Gnodex, Gnodey, Deltat, Lfs);
Use Inputpar
Implicit None

Real*8 Deltat, Lfs, Dt, Su
Real*8 Gvalue(1, (Numx+1)*(Numy+1)), GvalueU(1, (Numx+1)*(Numy+1)), GvalueV(1, (Numx+1)*(Numy+1))
Real*8 Gnodex(0:Numx), Gnodey(0:Numy)

Real*8 DX, DY
Real*8 X(-3:Numx+3), Y(-3:Numy+3)
Real*8 VelX(-3:Numx+3,-3:Numy+3), VelY(-3:Numx+3,-3:Numy+3)
Real*8 G(-3:Numx+3,-3:Numy+3)

Common /CommonData/ X, Y, DX, DY, VelX, VelY, G, Dt, Su

!============================= Data Transfer ============================
Dt                  = Deltat
Su                  = Lfs
X          (0:Numx) = Gnodex(0:Numx)
Y          (0:Numy) = Gnodey(0:Numy)
VelX(0:Numx,0:Numy) = transpose(reshape(GvalueU,(/Numy+1,Numx+1/)))
VelY(0:Numx,0:Numy) = transpose(reshape(GvalueV,(/Numy+1,Numx+1/)))
G   (0:Numx,0:Numy) = transpose(reshape(Gvalue ,(/Numy+1,Numx+1/)))

!==========Some other lines neglected here=================

End
!======================================== END PROGRAM =========================================

And the makefile is like:

# Compiler
CC = g++

# Debug option
DEBUG = false

# Source directory of codes
SRC1 = /home
SRC2 = $(SRC1)/Resources
SRC3 = $(SRC1)/Resources/Classes

OPT=-fopenmp -O2

ifdef $(DEBUG)
  PROG=test.out
else
  PROG=i.out
endif

# Linker
#LNK=-I$(MPI)/include -L$(MPI)/lib -lmpich -lopa -lmpl -lpthread

OBJS = libtseutil.a Calculate.o solveeq.o

OBJS_F=$(OBJS)
SUF_OPTS1=$(OBJS_F)
SUF_OPTS2=-I$(SRC2)/
SUF_OPTS3=-I$(SRC3)/
SUF_OPTS4=

# Details of compiling
$(PROG): $(OBJS_F)
    $(CC) $(OPT) -o $@ $(SUF_OPTS1)
%.o: $(SRC1)/%.cpp
    $(CC) $(OPT) -c $< $(SUF_OPTS2)
%.o: $(SRC2)/%.cpp
    $(CC) $(OPT) -c $< $(SUF_OPTS3)
%.o: $(SRC3)/%.cpp
    $(CC) $(OPT) -c $< $(SUF_OPTS4)
solveeq.o: $(SRC1)/solveeq.f90
    gfortran -c $<

# Clean
.PHONY: clean
clean:
    @rm -rf *.o *.oo *.log


来源:https://stackoverflow.com/questions/39239624/c-fortran-mixed-programming-undefined-reference-to-gfortran-reshape-r8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!