2016-08-31 3 views
1

Fortran 서브 루틴과 함께 C++ 코드를 컴파일 중입니다.C++/Fortran 혼합 프로그래밍 : 정의되지 않은 참조 '_gfortran_reshape_r8'

#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; 
} 

그리고 포트란 코드 같은 것입니다 : :이 C++ CPP 코드는 같다

!========================================================================== 
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 ========================================= 

는 첫째 명령을 사용하여 포트란 코드를 컴파일 :

 gfortran SolveEq.f90 -c -o SolveEq.o 

를, 그리고, C++/포트란 컴파일 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 [email protected] $(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 

그러나 오류는 다음과 같이 표시됩니다.

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 

어떻게 된 일입니까?

간단한 컴파일을 사용하여 혼합 된 컴파일을 테스트했습니다.

#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; 
} 

그리고 포트란 코드이었다 : :이 C++ 코드이었다

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

그것은 잘 작동 :

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 

그런 다음 컴파일 명령을 사용

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

간단한 프로그래밍을 테스트하기 위해 C++ 코드를 사용했습니다 : –

+1

아마 libgfortran과 링크해야합니까? –

+0

@ZetianRen, * nm * 또는 * objdump * 또는 컴파일러 모음의 해당 도구 (또는 운영 체제)가 있습니까? fortran_sum.o를보고 SolveEq_가 있는지 (또는 다른 변형 이름이 있는지) 확인할 수 있습니다. – blackpen

답변

1

함수 _gfortran_reshape_r8은 p입니다. gfortran에 의해 컴파일 된 코드에 의해 사용되는 라이브러리 기술. 단일 언어로 컴파일 할 때 이러한 라이브러리는 자동으로 링크됩니다. 연결을 수행하는 데 사용하는 프로그램이 무엇인지 알기 때문입니다. 혼합 된 코드를 링크 할 때 선택한 링커에 해당하지 않는 언어의 라이브러리를 찾아 명시 ​​적으로 명령 줄에 넣어야합니다. 보통 여기에서했던 것처럼 C++ 문법으로 연결하고 포트란 컴파일러의 라이브러리를 명시 적으로 추가합니다.

+0

감사합니다. 메이크 파일에서 링커 라인을 편집해야한다는 말입니까? –

+0

예, Fortran 라이브러리가 들어있는 라이브러리를 찾아 링커 명령 행에'-L' 플래그로 넣어야합니다. 또한 개별 라이브러리에 해당'-l' 플래그를 포함시켜야합니다. – Brick

+0

귀하의 질문에 대한 코멘트에서, 당신이 필요로하는 특정 라이브러리가'libgfortran' 인 것처럼 보입니다. 그래서 그것을 찾아서'-L' 플래그로 디렉토리를 넣으십시오 (예제의 다른 패키지에서했던 것처럼). '-lgfortran'을 사용하십시오. 더 많은 라이브러리가 필요 하겠지만 'gfortran'이 옳다. (나는 전에 이것을했지만 최근에는하지 않았다.) – Brick

1

저는 Fortran 언어에 약간 약합니다. 여러분의 포트란 코드를 컴파일하여 nm에 넣었을 때, 다음과 같이 나에게 알려주었습니다. "SolveEq_"기호가 없습니다. 그냥 "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_ 

편집 : 나는 "solveeq_"를 사용하는 경우 그것은 나를 위해 컴파일. (f.f90은 포트란 코드를 가지고)로 컴파일

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); 
} 

: 여기에 데모에 대한 간단한 코드 (MAIN.CPP)입니다

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

것 같다가, 2003 년 이후, 당신이 경우 C/C++에서 fortran 함수를 호출하고 싶다면 BIND를 사용할 수 있습니다 (추가 노력없이 fortran/fortran과 함께 사용하지 못할 수도 있음). 모든 일에

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

+0

감사! 함수 이름을 solveeq.f90으로 변경했습니다.이 문자는 모두 작은 글자로되어 있습니다. –

+0

Fortran은 대소 문자를 구분하지 않습니다. 컴파일러에 따라 일반적으로 모든 기호가 모두 대문자로 변환되거나 어셈블리의 모든 하위 기호로 변환됩니다. 또한 컴파일러와 함수 이름에 따라 심볼 이름에 0, 1 또는 2 개의 밑줄이 추가 될 수 있습니다. 언어 들간의 연결을 할 때이 점을 고려할 필요가 있지만 컴파일러에 의존한다는 점을 강조합니다. – Brick

0

감사합니다, 특히 @Brick 및 @blackpen. 문제가 해결되었습니다.

1), 명령 행에 -lgfortran을 추가하여 함수가 실행되도록하십시오. 그렇지 않으면`_gfortran_reshape_r8 '에 대한 정의되지 않은 참조가 표시됩니다.

2 ), 소문자로 .f90 함수의 이름 변경 "solveeq"기타가 표시됩니다 현명한 :

#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; 
} 
:`로 정의되지 않은 참조는 SolveGeq_ '

그래서 결국 내 통화 당은으로 변경

!========================================================================== 
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 ========================================= 

그리고 메이크 같은 것입니다 :

포트란 코드 .f90 같은입니다

# 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 [email protected] $(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 
+0

@blackpen에 의해 응답에 함수 이름의 대소 문자에 대한 관련 코멘트를 참조하십시오. – Brick