环境说明:
- Ubuntu版本:v22.04 LTS
- .NET版本:v8.0.110
- GFortran版本:v11.4.0
Fortran_6">安装Fortran编译器
在Ubuntu上安装Fortran编译器:
# 更新包列表
sudo apt update# 安装gfortran编译器
sudo apt install gfortran
创建.NET控制台项目
创建.NET控制台程序,首先创建一个新的.NET项目:
# 创建新的控制台项目
dotnet new console -n FortranTest
cd FortranTest
项目文件结构如下:
FortranTest/
├── fortran/
│ ├── calc.f90
├── Program.cs
├── FortranTest.csproj
└── README.md
// FortranTest.csproj
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><ItemGroup><None Include="libcalc.so"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None></ItemGroup>
</Project>
// Program.cs
using System.Runtime.InteropServices;class Program
{// 导入Fortran函数[DllImport("libcalc.so", CallingConvention = CallingConvention.Cdecl)]private static extern void array_sum([In] double[] arr,int size,out double result);[DllImport("libcalc.so", CallingConvention = CallingConvention.Cdecl)]private static extern void array_average([In] double[] arr,int size,out double result);static void Main(string[] args){try{// 测试数据double[] testArray = { 1.0, 2.0, 3.0, 4.0, 5.0 };// 计算总和double sum = 0.0;array_sum(testArray, testArray.Length, out sum);Console.WriteLine($"数组总和: {sum}");// 计算平均值double average = 0.0;array_average(testArray, testArray.Length, out average);Console.WriteLine($"数组平均值: {average}");}catch (Exception ex){Console.WriteLine($"错误: {ex.Message}");}}
}
// calc.f90
module calculationuse iso_c_bindingimplicit nonecontains! 一个简单的数组求和函数subroutine array_sum(arr, size, result) bind(c, name='array_sum')use iso_c_bindingimplicit noneinteger(c_int), value :: sizereal(c_double), intent(in) :: arr(size)real(c_double), intent(out) :: resultinteger :: iresult = 0.0d0do i = 1, sizeresult = result + arr(i)end doend subroutine array_sum! 一个简单的数组平均值函数subroutine array_average(arr, size, result) bind(c, name='array_average')use iso_c_bindingimplicit noneinteger(c_int), value :: sizereal(c_double), intent(in) :: arr(size)real(c_double), intent(out) :: resultcall array_sum(arr, size, result)result = result / sizeend subroutine array_average
end module calculation
# 编译Fortran代码
cd fortran
gfortran -c -fPIC calc.f90 -o calc.o
gfortran -shared calc.o -o libcalc.so# 复制.so文件到.NET项目目录
cp libcalc.so ../# 编译和运行.NET程序
cd ..
dotnet build
dotnet run
能否不复制so文件到项目目录?
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><ItemGroup><None Include="fortran/libcalc.so"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None></ItemGroup>
</Project>
此时,build项目后,会在输出目录新增文件“FortranTest/bin/Debug/net8.0/fortran/libcalc.so”,修改代码如下,同样可以正常运行项目
// 导入Fortran函数
[DllImport("fortran/libcalc.so", CallingConvention = CallingConvention.Cdecl)]
private static extern void array_sum([In] double[] arr,int size,out double result);[DllImport("fortran/libcalc.so", CallingConvention = CallingConvention.Cdecl)]
private static extern void array_average([In] double[] arr,int size,out double result);
不建议直接在DllImport中使用相对路径。这可能会导致运行时路径解析问题。为了更可靠的路径解析,可以修改代码如下:
using System.Runtime.InteropServices;class Program
{// 导入Fortran函数[DllImport("libcalc.so", CallingConvention = CallingConvention.Cdecl)]private static extern void array_sum([In] double[] arr,int size,out double result);[DllImport("libcalc.so", CallingConvention = CallingConvention.Cdecl)]private static extern void array_average([In] double[] arr,int size,out double result);static void Main(string[] args){try{// 添加库文件搜索路径解析器NativeLibrary.SetDllImportResolver(typeof(Program).Assembly, (libraryName, assembly, searchPath) =>{// 获取程序运行目录下的 fortran 子目录string libraryPath = Path.Combine(AppContext.BaseDirectory, "fortran", libraryName);return NativeLibrary.Load(libraryPath);});// 测试数据double[] testArray = { 1.0, 2.0, 3.0, 4.0, 5.0 };// 计算总和double sum = 0.0;array_sum(testArray, testArray.Length, out sum);Console.WriteLine($"数组总和: {sum}");// 计算平均值double average = 0.0;array_average(testArray, testArray.Length, out average);Console.WriteLine($"数组平均值: {average}");}catch (Exception ex){Console.WriteLine($"错误: {ex.Message}");}}
}