Ubuntu中使用C#调用Fortran编译so文件

ops/2024/12/13 3:38:23/

环境说明:

  • 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}");}}
}

http://www.ppmy.cn/ops/141422.html

相关文章

基于51单片机64位病床呼叫系统设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机病床呼叫系统设计( proteus仿真程序设计报告原理图讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0095 1. 主要功能&#xff1a; 基于51单片机的病床呼叫系统proteus仿…

BA和CS算法中的Levy飞行策略

Levy飞行策略通过模拟自然界中动物的长距离迁徙行为&#xff0c;指导粒子进行更大范围的搜索&#xff0c;有助于算法快速找到全局最优解。它是一种具有独特优势的随机行为策略&#xff0c;模拟随机游走或搜索过程中的步长和方向&#xff0c;其步长的概率分布为重尾分布&#xf…

说下JVM中一次完整的GC流程?

大家好&#xff0c;我是锋哥。今天分享关于【说下JVM中一次完整的GC流程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说下JVM中一次完整的GC流程&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在JVM中&#xff0c;垃圾回收&#xff08;GC&am…

DVWA亲测sql注入漏洞

LOW等级 我们先输入1 我们加上一个单引号&#xff0c;页面报错 我们看一下源代码&#xff1a; <?php if( isset( $_REQUEST[ Submit ] ) ) { // Get input $id $_REQUEST[ id ]; // Check database $query "SELECT first_name, last_name FROM users WHERE user_id …

LLaMA-Factory 上手即用教程

LLaMA-Factory 是一个高效的大型语言模型微调工具&#xff0c;支持多种模型和训练方法&#xff0c;包括预训练、监督微调、强化学习等&#xff0c;同时提供量化技术和实验监控&#xff0c;旨在提高训练速度和模型性能。 官方开源地址&#xff1a;https://github.com/hiyouga/L…

【蓝桥杯Day1】:LCR 018. 验证回文串,left++<right--?

1&#xff1a;isalnum() 函数说明&#xff1a; 检查参数c,是否为英文字母或阿拉伯数字。 2.int toupper( int c)&#xff0c;toupper():将字母转位大写。 3.int tolower( int c)&#xff0c;tolower():将字母转为小写。 下面是我自己写的&#xff0c;感觉写的有点搓。 特别注…

系统安全——访问控制访问控制

访问控制 概念 什么是访问控制 access control 为用户对系统资源提供最大限度共享的基础上&#xff0c;对用户的访问权进行管理&#xff0c;防止对信息的非授权篡改和滥用 ​ 访问控制作用 保证用户在系统安全策略下正常工作 拒绝非法用户的非授权访问请求 拒绝合法用户越权…

【Java-数据结构篇】Java 中栈和队列:构建程序逻辑的关键数据结构基石

我的个人主页 我的专栏&#xff1a;Java-数据结构&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 一、引言 1. 栈与队列在编程中的角色定位 栈和队列作为两种基本的数据结构&#xff0c;在众多编程场景中都有着独特的地位。它们为数据的有序…