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