2016-08-31 3 views
1

への未定義参照私は、Fortranのサブルーチンと一緒にC++コードをコンパイルしています。 C++ CPPコードは次のようである: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; 
} 

とFortranコードは次のようである:

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

は、まずコマンドを使用して、Fortranコードコンパイル:

 gfortran SolveEq.f90 -c -o SolveEq.o 

をそしてC++/Fortranのコンパイル

# 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 

はどのようにこれが起こるん?しかし、エラーがあることを示し

I混合コンパイルをテストするための単純なケースを用います。 C++コードはでした:

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

およびFortranコードはでした:

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 

は、次にコンパイルするためのコマンドを使用:

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

これはよく働いた:

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++構文にリンクし、Fortranコンパイラのライブラリを明示的に追加します。

+0

ありがとうございます。あなたは私のリンカーラインをメイクファイルで編集する必要があるのですか? –

+0

はい、Fortranライブラリを含むライブラリを見つけて、そのライブラリを '-L'フラグを付けたリンカコマンドラインに置く必要があります。個々のライブラリに対応する '-l'フラグを含める必要もあります。 – Brick

+0

あなたの質問のコメントから、あなたが必要とする特定のライブラリが 'libgfortran'であるように見えるので、それを見つけて' -L'フラグでディレクトリを置きます(あなたの例では他のパッケージの場合と同じです)。 '-lgfortran'を指定してください。より多くの図書館が必要だと分かるかもしれませんが、 'gfortran'は正しく聞こえます。 (私は前にこれをやったことがありますが、最近ではありません) – Brick

1

私はFortran言語で少し弱いです。私があなたの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_" を使用したとき それは私のためにコンパイル。もしあればそれは、2003年以来、思わ

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

:(f.f90は、Fortranコードを持っている)として

それをコンパイル
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に)簡略化されています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」他の賢明それが表示されます: `SolveGeq_」

に未定義の参照をだから、最終的には私の.cppファイルがに変更されています

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

Fortranコードの.F90は次のようである:

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

そしてメイクファイルは次のようである:

# 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