今天单位GX姐给我们辅导了fortran和C语言的混编,培训内容如下,在此简单的介绍一下。
C与Fortran混合编程中,结构体在C语言和Fortran中都要定义一遍,并且内存和顺序都要一致,但名字可以不一样。
1.linux操作系统
RedHat Enterprise Linux Server release 6.6
2.编译器
C语言编译:gcc
Fortran语言编译:ifort
3.总体思路:
Fortran语言编写库函数,自己写一个makefile编译成可静态库
C语言编写可执行文件,自己写一个makefile编译成可执行文件,调用Fortran的静态库。
3.1Fortran库:
(1)Mod文件编译
Mod文件定义了Fortran与C公用的一些结构体,相当于C语言中的头文件。
使用下述命令可编译成*.mod文件,在makefile中引用即可
Ifort
-c -fPIC
-module
mod文件存放的绝对路径源文件存放的绝对路径
-o目标文件存放的绝对路径
注意:Fortran与C语言共用的结构体,定义时一定要保证变量的类型、大小、顺序一致性,因为调用库函数时是按照内存的顺序存放读取参数变量,而不是按照变量名读取的。
(2)源代码
以CO2反演模块为例:
包含四个源文件:tansat.f90
C语言调用的库函数的接口
tansat_io_def.f90变量类型的定义
tansat_io_input.f90库函数输入结构体的定义(L1b、T639)
tansat_io_output.f90库函数输出结构的定义(L2)
以上三个文件通过Ifort
-c -fPIC
-module生成mod文件,include到第一个f90文件中,将第一个文件编译成可执行程序。
tansat.f90
SubroutineTanSat(Input,Output)编译成库用Subroutine,可执行程序用program
fortune中!代表注释
!
!TanSat XCO2 retrieval algorithm V2.0
!CO2 1.61, CO2 2.04 and O2A band
!Creat by Dongxu Yang (Dr.)
!Institude of Atmospheric Physics, Chinese Academy of
Science
!
USE
tansat_Retrieval
mod文件
! Inclue the input/output type
defination
USE tansat_io_input
mod文件
USE
tansat_io_output
mod文件
IMPLICIT NONE强制标识符先定义后使,fortran里面有一项不好的功能,就是变量不经定义就可以使用,而且根据变量的开始字母自行给变量规定类型,加上implicitnone
后可以防止这个东西
TYPE(tansat_io_input_L1B_HSCO2_HDF) ::
Input
TYPE(tansat_io_output_L2_HSCO2_HDF) ::
Output
INTEGER(KIND=4) ::
Input_fake !后面的类型是4个字节
INTEGER(KIND=4) ::
Output_fake
CHARACTER(LEN=256) ::
pathin
pathin = ''
pathin(1:Input%tansat_path%pathlen)
=Input%tansat_path%path(1:Input%tansat_path%pathlen)
print*,trim(pathin)//'data/log.tax'
!字符串连接,trim为fortune去掉空格
CALLtansat_Retrieval_ctl(Input_fake,Output_fake,pathin)调用子函数
END!结束代码的编写
注意:a.fortran对字符串的处理和c不一样,C语言字符串一般都以'\0'结束的,以数据0补足字符串的,所以len算出来的就是字符串实际的长度;而fortran是以空格补足字符串的,所以要用len_trim计算字符串实际的长度。所以当C语言将一个补零后的字符串传递给fortran时,fortran读到'\0'并不认为是结束,还会继续读取后面的0。所以需要告诉fortran
c语言中字符串的长度,把C语言的字符串逐个赋值给fortran,并用trim函数去掉fortran中的空格,才能进行字符串连接。
Fortran中连接字符串的函数是//。
tansat_io_input.f90
MODULE
tansat_io_input表明该文件是mod文件
USE
tansat_io_num_def,ONLY:INT_IO,DBP_IO,SRT_IO,FLT_IO,LNG_IO,USS_IO,UNS_IO
使用到的mod文件
IMPLICIT NONE
PUBLIC ::
tansat_io_input_L1B_HSCO2_META
PUBLIC
::tansat_io_input_L1B_HSCO2_DIMENSION
PUBLIC ::
tansat_io_input_L1B_HSCO2_HDF
。。。。。。。。
TYPE
tansat_io_input_L1B_HSCO2_DIMENSIONS
!定义变量
INTEGER(KIND=INT_IO) :: AncFile
INTEGER(KIND=INT_IO) :: Frame
END TYPE
tansat_io_input_L1B_HSCO2_DIMENSIONS
。。。。。。。。
ENDMODULE tansat_io_input
(3)makefile
编写Fortran程序,写makefile文件如下:
HOME= /usr/local
HOME1= /home/tansat/TanSat_V2.0T/debug
HOME2= /home/tansat/TanSat_V2.0T
FC=ifort
OUT_SRCS=
\源文件
../src/tansat.f90
OUT_OBJS=
\目标文件
./tansat.o
#OUT_SRCS=$(wildcard../src/*.f90)
#DIR=$(notdir$(SRCS))
#OUT_OBJS=$(patsubst%.f90,%.o,$(OUT_SRCS))
INCLUDE=
\包含的头文件路径
-I$(HOME)/hdf-5/include\
-I$(HOME)/netcdf-4/include\
-I$(HOME)/netcdf-fortran-4/include\
-I$(HOME2)/mod此处为包含的mod文件路径
ALLFLAG=
\包含的库,前面是路径,后面是库的名称
-L$(HOME)/hdf-5/lib-lhdf5 -lhdf5_fortran
-lhdf5_hl -lhdfhl_fortran \
-L$(HOME)/netcdf-4/lib-lnetcdf \
-L$(HOME)/netcdf-fortran-4/lib-lnetcdff \
-L/../lib/tansat_acc.so-L/../lib/tansat_fwd.so
-L/../lib/tansat_main.so
-L/../lib/tansat_lapack.so
!注意动态库和静态库的区别。动态库需要将所有路径都写上
all:libtansat.a
libtansat.a:$(OUT_OBJS)
ar -crv "libtansat.a"$(OUT_OBJS)
./%.o:../src/%.f90
$(FC) $(INCLUDE) -O0 -g -c-o"$@" "$
$(ALLFLAG)
.PHONY:clean
clean:
rm -f $(OUT_OBJS) libtansat.a
然后打开终端,运行下述命令:
makeclean
make
3.2
C语言可执行文件
必须强调的是,在C语言中调用Fortran库前,需要进行函数声明。
与C语言函数声明不同的是,Fortran函数后面需要加_,然后才可以在语言中调用。
(1)源文件
在*.cpp文件开始对Fortran函数进行声明:
#include
extern "C" void tansat_(
//注意下划线
L1B_HSCO2_HDF *l1b_hdf,
L2_HSCO2_HDF *l2_hdf
);
。。。。。。。
intProcessor::accelerate(CWriteLog
*log)
{
int i,ret;
printf("Start
Retrievalfunction!!!\n");
sounding_index = 5;
for(i=0;i
{
l1b_hdf.instrument_header
=RW->l1b_instrument_header[sounding_index];
l1b_hdf.sounding_measurements
=RW->l1b_sounding_measurements;
l1b_hdf.sounding_geometry
=RW->l1b_geometry;
for(int j= 0;j<256;j++)
{
l1b_hdf.datapath.strDataPath[j]= ' ';
}
strcpy(l1b_hdf.datapath.strDataPath,RW->strDataPath);
l1b_hdf.datapath.len
=strlen(l1b_hdf.datapath.strDataPath);
printf("l1b_hdf.strDataPath:%s\n",l1b_hdf.datapath.strDataPath);
printf("len:%d\n",l1b_hdf.datapath.len);
memcpy(l1b_hdf.t639.pres,RW->t639.pres,36*sizeof(float));
memcpy(l1b_hdf.t639.temp,RW->t639.temp,36*sizeof(float));
memcpy(l1b_hdf.t639.sh,RW->t639.sh,36*sizeof(float));
l1b_hdf.t639.pres0 =RW->t639.pres0;
l1b_hdf.t639.temp0 =RW->t639.temp0;
l1b_hdf.t639.sh0 =RW->t639.sh0;
tansat_(&l1b_hdf,&l2_hdf);
//注意下划线
RW->l2_HSCO2[i].Particles
=l2_hdf.Particles;
RW->l2_HSCO2[i].Surface =l2_hdf.Surface;
}
printf("endRetrievalfunction!!!\n");
return 0;
}
(2)makefile
CXXFLAGS=-O0-g -Wall -fmessage-length=0
CXX=g++
LIB+= -lconfig -lTanhdf
-ltimestring -lhdf5 -lhdf5_fortran -lhdf5_hl
-lhdf5hl_fortran -ltansat -lnetcdf -lnetcdff包含的静态库
LIB+=/TANTDP/LIB/libCWriteLog_TAN.so包含的动态库
LIB+=/TANTDP/LIB/libParamDll_TAN.so包含的动态库
LIB+=../lib/tansat_acc.so包含的动态库
LIB+=../lib/tansat_main.so包含的动态库
LIB+=../lib/tansat_lapack.so包含的动态库
LIB+=../lib/tansat_fwd.so包含的动态库
LIB+=-I/home/T/src/include/头文件路径
LIB+=-I/usr/local/hdf-5/include/头文件路径
LIB+=-L/home/T/lib/静态库的路径
LIB+=-L/usr/local/hdf-5/lib/静态库的路径
LIB+=-L/usr/local/netcdf-4/lib/静态库的路径
LIB+=-L/usr/local/netcdf-fortran-4/lib/静态库的路径
SRCS=$(wildcard../src/*.cpp)
#DIR=$(notdir$(SRCS))
OBJS=$(patsubst%.cpp,%.o,$(SRCS))
EXEC=TANSAT
$(EXEC):$(OBJS)
$(CXX) -o $@ $^ $(LIB)
@echo "---------OK--------"
@echo "---------OK--------"
@echo "---------OK--------"
.cpp.o:
$(CXX) -o $@ -c $< $(CXXFLAGS)
clean:
rm -f $(OBJS)
然后打开终端,运行下述命令:
makeclean
make
4.运行可执行程序
./TANSAT../xml/input.xml ../xml/output.xml
以上工作中,forturan要做的工作:
fortran编译好三个mod,并将mod
include到主程序f90中,将主程序编译成.a文件。
C语言要做的工作:
首先将fortran定义的mod文件中结构体在C语言头文件中按顺序重新定义一下,在makefile中将fortran的库文件引用进来(通过so来引用a),然后在需要调用该库函数的cpp上将fortran定义的库函数extern声明一下,编译后就可以调用fortran函数了。
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/fortranbc/2248.html