1

我正在与 Fortran 子例程一起编译 C++ 代码。C++ cpp 代码如下:

#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

然后使用 makefile 一起编译 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 $@ $(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

这是怎么发生的?

我用一个简单的案例来测试混合编译。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
4

3 回答 3

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_”时,它为我编译。这是演示的简化代码(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);
}

编译为(f.f90 有 fortran 代码):

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

看来,自 2003 年以来,如果您想从 C/C++ 调用 fortran 函数,您可以使用 BIND(它可能不适用于 fortran/fortran,尽管没有更多的额外努力)。

子程序 SolveEq(F) BIND(C,NAME="SolveMyEquation")
实 Gvalue, GvalueU, GvalueV, Gnodex, Gnodey, Deltat, Lfs
结尾

于 2016-08-31T03:55:13.653 回答
1

该函数_gfortran_reshape_r8是库的一部分,由gfortran. 当您以单一语言编译时,此类库会自动链接,因为您用于进行链接的任何程序都知道它们。当您链接混合代码时,您需要找到与您选择的链接器不对应的语言的库并将其显式放入命令行。通常您使用 C++ 语法链接,就像您在此处所做的那样,并显式添加 fortran 编译器的库。

于 2016-08-31T02:07:20.297 回答
0

感谢每一个人,尤其是@Brick 和@blackpen。问题已解决。

1),在命令行中添加-lgfortran,这样函数就会显示:undefined reference to `_gfortran_reshape_r8'。

2), 将 .f90 函数的名称更改为小写字母“solveeq”,否则将显示:undefined reference to `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 =========================================

而makefile是这样的:</p>

# 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
于 2016-09-02T03:20:40.277 回答