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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM