Stupid && 祖传Fortran代码救赎之路(编译Dll)

Stupid && 祖传Fortran代码救赎之路(编译Dll)

gfortran编译动态库

在Windows平台下,Intel Fortran安装过于庞大且费事(现在集成到OneAPI上了,安装下需要60G),之前在VS2019上折腾了好久,最后Debug调试不显示过程变量,吐了。。。

后来决定直接用gfortran+gdb+VScode来做Fortran程序的调试与编译。在此记录一下,如何时使用gfortran编译Dll,以及如何使用C++、Matlab调用Fortran生成的Dll库。

Fortran测试程序(test.f90)

各种不同的Fortran源程序定义接口的方法看到过不少,比如传送门

最后发现以下这种方式最为简单,且有效,具体为啥我也不清楚。

测试程序中test1()没有输入输出,test2(array,Num)需要返回一个数组(Fortran函数大都需要数组作为输入输出)。

subroutine test1() BIND(C,NAME="test1")
  implicit none
  PRINT *, 'I am a function'
  return
end 

subroutine test2(array,Num)  BIND(C,NAME="test2")
  implicit none
  INTEGER,INTENT(IN):: Num
  REAL*8,INTENT(OUT):: array(1:Num)
  INTEGER :: I
  DO I=1,Num
    array(I)=I
  ENDDO
end 

编译命令

编译成为动态库

> gfortran -c -O3 f90
> gfortran -shared -fPIC -o Test.dll *.o

编译完成即可得到名为\(Test.dll\)的动态链接库

C++调用Fortran动态库(DLL)

采用显示调用的方式调用动态库,在Windows平台下,借助\(Windows.h\)中的\(LoadLibrary,GetProcAddress,FreeLibrary\)动态加载,使用动态库。

测试程序

#include <iostream>
#include <Windows.h>

using namespace std;
typedef void(*test1Func)();
typedef void(*test2Func)(double*, int*);

int main(void)
{
	//加载DLL库
	HINSTANCE hDLL = LoadLibrary(L"Test.dll");
	//定义函数指针
	test1Func test1;    // Function pointer
	test2Func test2;

	if (hDLL != NULL)
	{
		//获得函数地址
		test1 = (test1Func)GetProcAddress(hDLL, "test1");
		test2 = (test2Func)GetProcAddress(hDLL, "test2");

		if (!test1 && !test2)
		{
			// handle the error
			std::cout << "Open the dll error" << std::endl;
            //卸载函数库
			FreeLibrary(hDLL);
			return -1;
		}
		else
		{
			test1();
			int Num = 10;
			double* myarray = new double[Num];
			test2(myarray, &Num);
			for (int i = 0; i < Num; ++i)
				cout << myarray[i] << endl;
			FreeLibrary(hDLL);
		}
	}
	return 0;
}

输出

 I am a function
1
2
3
4
5
6
7
8
9
10

Matlab 调用.DLL

现在已经得到gFortran编译的Dll库,在Matlab中,可以使用calllib方法调用函数,但是需要存在函数声明,所以首先编写C头文件,存放函数声明。

函数声明头文件

//Test.h
void test1();
void test2(double*,int * );

Matlab Demo

clc;clear all;
loadlibrary('Test.dll','Test.h');
% test1 函数没有参数,也没有返回值,不知道咋调用
% calllib('Test','test1');
Num=10;
myarray=zeros(Num,1);
[myarray,NN]=calllib('Test','test2',myarray,Num);
myarray
NN
unloadlibrary Test

输出结果

myarray =

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10


NN =

  int32

   10

参考链接

Windows下gfortran编译DLL

Windows下安装InterFortran

Matlab调用Fortran编译的DLL

posted @ 2021-12-01 14:07  陈橙橙  阅读(1141)  评论(0编辑  收藏  举报