Stupid && 祖傳Fortran程式碼救贖之路(編譯Dll)

陳橙橙發表於2021-12-01

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 -static -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

相關文章