环境说明:
- Ubuntu版本:v22.04 LTS
- .NET版本:v8.0.110
- GFortran版本:v11.4.0
安装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 calculation
use iso_c_binding
implicit none
contains
! 一个简单的数组求和函数
subroutine array_sum(arr, size, result) bind(c, name='array_sum')
use iso_c_binding
implicit none
integer(c_int), value :: size
real(c_double), intent(in) :: arr(size)
real(c_double), intent(out) :: result
integer :: i
result = 0.0d0
do i = 1, size
result = result + arr(i)
end do
end subroutine array_sum
! 一个简单的数组平均值函数
subroutine array_average(arr, size, result) bind(c, name='array_average')
use iso_c_binding
implicit none
integer(c_int), value :: size
real(c_double), intent(in) :: arr(size)
real(c_double), intent(out) :: result
call array_sum(arr, size, result)
result = result / size
end 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}");
}
}
}
标签:C#,double,sum,Fortran,result,Ubuntu,array,average,size
From: https://www.cnblogs.com/vinciyan/p/18598688