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