.NET7的AOT的使用

这篇具有很好参考价值的文章主要介绍了.NET7的AOT的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

其实,规划这篇文章有一段时间了,但是比较懒,所以一直拖着没写。

最近时总更新太快了,太卷了,所以借着 .NET 7 正式版发布,熬夜写完这篇文章,希望能够追上时总的一点距离。

本文主要介绍如何在 .NET 和 Go 语言中如何生成系统(Windows)动态链接库,又如何从代码中引用这些库中的函数。

在 .NET 部分,介绍如何使用 AOT、减少二进制文件大小、使用最新的 [LibraryImport] 导入库函数;

在 Go 语言部分,介绍如何使用 GCC 编译 Go 代码、如何通过 syscall 导入库函数。

在文章中会演示 .NET 和 Go 相互调用各自生成的动态链接库,以及对比两者之间的差异。

C# 部分

环境要求

SDK:.NET 7 SDKDesktop development with C++ workload

IDE:Visual Studio 2022

Desktop development with C++ workload 是一个工具集,里面包含 C++ 开发工具,需要在 Visual Studio Installer 中安装,如下图红框中所示。

.NET7的AOT的使用

创建一个控制台项目

首先创建一个 .NET 7 控制台项目,名称为 CsharpAot。

打开项目之后,基本代码如图所示:

.NET7的AOT的使用

我们使用下面的代码做测试:

publicclassProgram
{
    staticvoidMain()
    {
        Console.WriteLine("C# Aot!");
        Console.ReadKey();
    }
}

体验 AOT 编译

这一步,可以参考官方网站的更多说明:

为了能够让项目发布时使用 AOT 模式,需要在项目文件中加上 <PublishAot>true</PublishAot> 选项。

.NET7的AOT的使用

然后使用 Visual Studio 发布项目。

发布项目的配置文件设置,需要按照下图进行配置。

.NET7的AOT的使用
AOT 跟 生成单个文件 两个选项不能同时使用,因为 AOT 本身就是单个文件。

配置完成后,点击 发布,然后打开 Release 目录,会看到如图所示的文件。

.NET7的AOT的使用

.exe 是独立的可执行文件,不需要再依赖 .NET Runtime 环境,这个程序可以放到其他没有安装 .NET 环境的机器中运行。

然后删除以下三个文件:

    CsharpAot.exp
    CsharpAot.lib
    CsharpAot.pdb
光用 .exe 即可运行,其他是调试符号等文件,不是必需的。

剩下 CsharpAot.exe 文件后,启动这个程序:

.NET7的AOT的使用

C# 调用库函数

这一部分的代码示例,是从笔者的一个开源项目中抽取出来的,这个项目封装了一些获取系统资源的接口,以及快速接入 Prometheus 监控。

因为后续代码需要,所以现在请开启 “允许不安全代码”。

本小节的示例是通过使用 kernel32.dll 去调用 Windows 的内核 API(Win32 API),调用 GlobalMemoryStatusEx 函数 检索有关系统当前使用物理内存和虚拟内存的信息

使用到的 Win32 函数

关于 .NET 调用动态链接库的方式,在 .NET 7 之前,通过这样调用:

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internalstaticextern Boolean GlobalMemoryStatusEx(ref MemoryStatusExE lpBuffer);

在 .NET 7 中,出现了新的操作方式 [LibraryImport]。

文档是这样介绍的:

Indicates that a source generator should create a functionfor marshalling arguments instead of relying on the runtime to generate an equivalent marshalling function at run time.

指示源生成器应创建用于编组参数的函数,而不是依赖运行库在运行时生成等效的编组函数。

简单来说,就是我们要使用 AOT 写代码,然后代码中引用到别的动态链接库时,需要使用 [LibraryImport] 引入这些函数。

笔者没有在 AOT 下测试过 [DllImport],读者感兴趣可以试试。

新建两个结构体 MEMORYSTATUS.cs、MemoryStatusExE.cs 。

MEMORYSTATUS.cs :

publicstruct MEMORYSTATUS
{
    internal UInt32 dwLength;
    internal UInt32 dwMemoryLoad;
    internal UInt32 dwTotalPhys;
    internal UInt32 dwAvailPhys;
    internal UInt32 dwTotalPageFile;
    internal UInt32 dwAvailPageFile;
    internal UInt32 dwTotalVirtual;
    internal UInt32 dwAvailVirtual;
}

MemoryStatusExE.cs :

publicstruct MemoryStatusExE
{
    ///<summary>/// 结构的大小,以字节为单位,必须在调用 GlobalMemoryStatusEx 之前设置此成员,可以用 Init 方法提前处理///</summary>///<remarks>应当使用本对象提供的 Init ,而不是使用构造函数!</remarks>internal UInt32 dwLength;

    ///<summary>/// 一个介于 0 和 100 之间的数字,用于指定正在使用的物理内存的大致百分比(0 表示没有内存使用,100 表示内存已满)。///</summary>internal UInt32 dwMemoryLoad;

    ///<summary>/// 实际物理内存量,以字节为单位///</summary>internal UInt64 ullTotalPhys;

    ///<summary>/// 当前可用的物理内存量,以字节为单位。这是可以立即重用而无需先将其内容写入磁盘的物理内存量。它是备用列表、空闲列表和零列表的大小之和///</summary>internal UInt64 ullAvailPhys;

    ///<summary>/// 系统或当前进程的当前已提交内存限制,以字节为单位,以较小者为准。要获得系统范围的承诺内存限制,请调用GetPerformanceInfo///</summary>internal UInt64 ullTotalPageFile;

    ///<summary>/// 当前进程可以提交的最大内存量,以字节为单位。该值等于或小于系统范围的可用提交值。要计算整个系统的可承诺值,调用GetPerformanceInfo核减价值CommitTotal从价值CommitLimit///</summary>internal UInt64 ullAvailPageFile;

    ///<summary>/// 调用进程的虚拟地址空间的用户模式部分的大小,以字节为单位。该值取决于进程类型、处理器类型和操作系统的配置。例如,对于 x86 处理器上的大多数 32 位进程,此值约为 2 GB,对于在启用4 GB 调整的系统上运行的具有大地址感知能力的 32 位进程约为 3 GB 。///</summary>internal UInt64 ullTotalVirtual;

    ///<summary>/// 当前在调用进程的虚拟地址空间的用户模式部分中未保留和未提交的内存量,以字节为单位///</summary>internal UInt64 ullAvailVirtual;


    ///<summary>/// 预订的。该值始终为 0///</summary>internal UInt64 ullAvailExtendedVirtual;

    internalvoidRefresh()
    {
        dwLength = checked((UInt32)Marshal.SizeOf(typeof(MemoryStatusExE)));
    }
}

定义引用库函数的入口:

publicstaticpartialclassNative
{

    ///<summary>/// 检索有关系统当前使用物理和虚拟内存的信息///</summary>///<param name="lpBuffer"></param>///<returns></returns>
    [LibraryImport("Kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internalstaticpartial Boolean GlobalMemoryStatusEx(ref MemoryStatusExE lpBuffer);
}

然后调用 Kernel32.dll 中的函数:

publicclassProgram
{
    staticvoidMain()
    {
        var result = GetValue();
        Console.WriteLine($"当前实际可用内存量:{result.ullAvailPhys / 1000 / 1000}MB");
        Console.ReadKey();
    }
    
    ///<exception cref="Win32Exception"></exception>publicstatic MemoryStatusExE GetValue()
    {
        var memoryStatusEx = new MemoryStatusExE();
        // 重新初始化结构的大小
        memoryStatusEx.Refresh();
        // 刷新值if (!Native.GlobalMemoryStatusEx(ref memoryStatusEx)) thrownew Win32Exception("无法获得内存信息");
        return memoryStatusEx;
    }
}

使用 AOT 发布项目,执行 CsharpAot.exe 文件。

.NET7的AOT的使用

减少体积

在前面两个例子中可以看到 CsharpAot.exe 文件大约在 3MB 左右,但是这个文件还是太大了,那么我们如何进一步减少 AOT 文件的大小呢?

需要注意的是,裁剪是没有那么简单的,里面配置繁多,有一些选项不能同时使用,每个选项又能带来什么样的效果,这些选项可能会让开发者用得很迷茫。

经过笔者的大量测试,笔者选用了以下一些配置,能够达到很好的裁剪效果,供读者测试。

首先,引入一个库:

	<ItemGroup>
		<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" />
	</ItemGroup>

接着,在项目文件中加入以下选项:

		<!--AOT 相关-->
		<PublishAot>true</PublishAot>	
		<TrimMode>full</TrimMode>
		<RunAOTCompilation>True</RunAOTCompilation>
		<PublishTrimmed>true</PublishTrimmed>
		<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
		<PublishReadyToRunEmitSymbols>false</PublishReadyToRunEmitSymbols>
		<DebuggerSupport>false</DebuggerSupport>
		<EnableUnsafeUTF7Encoding>true</EnableUnsafeUTF7Encoding>
		<InvariantGlobalization>true</InvariantGlobalization>
		<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
		<MetadataUpdaterSupport>true</MetadataUpdaterSupport>
		<UseSystemResourceKeys>true</UseSystemResourceKeys>
		<IlcDisableReflection >true</IlcDisableReflection>

最后,发布项目。

吃惊!生成的可执行文件只有 1MB 了,而且还可以正常执行。

.NET7的AOT的使用

笔者注:虽然现在看起来 AOT 的文件很小了,但是如果使用到 HttpClient、System.Text.Json 等库,哪怕只用到了一两个函数,最终包含这些库以及这些库使用到的依赖,生成的 AOT 文件会大得惊人。

所以,如果项目中使用到其他 nuget 包的时候,别想着生成的 AOT 能小多少!

C# 导出函数

在 C 语言中,导出一个函数的格式可以这样:

// MyCFuncs.h#ifdef __cplusplusextern"C" {  // only need to export C interface if// used by C++ source code#endif

__declspec( dllimport ) voidMyCFunc();
__declspec( dllimport ) voidAnotherCFunc();

#ifdef __cplusplus
}
#endif

当代码编译之后,我们就可以通过引用生成的库文件,调用 MyCFunc、AnotherCFunc 两个方法。

如果不导出的话,别的程序是无法调用库文件里面的函数。

因为 .NET 7 的 AOT 做了很多改进,因此,.NET 程序也可以导出函数了。

新建一个项目,名字就叫 CsharpExport 吧,我们接下来就在这里项目中编写我们的动态链接库。

添加一个 CsharpExport.cs 文件,内容如下:

using System.Runtime.InteropServices;

namespaceCsharpExport
{
    publicclassExport
    {
        [UnmanagedCallersOnly(EntryPoint = "Add")]
        publicstaticintAdd(int a, int b)
        {
            return a + b;
        }
    }
}

然后在 .csproj 文件中,加上 PublishAot 选项。

.NET7的AOT的使用

然后通过以下命令发布项目,生成链接库:

 dotnet publish -p:NativeLib=Shared -r win-x64 -c Release
.NET7的AOT的使用

看起来还是比较大,为了继续裁剪体积,我们可以在 CsharpExport.csproj 中加入以下配置,以便生成更小的可执行文件。

		<!--AOT 相关-->
		<PublishAot>true</PublishAot>
		<TrimMode>full</TrimMode>
		<RunAOTCompilation>True</RunAOTCompilation>
		<PublishTrimmed>true</PublishTrimmed>
		<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
		<PublishReadyToRunEmitSymbols>false</PublishReadyToRunEmitSymbols>
		<DebuggerSupport>false</DebuggerSupport>
		<EnableUnsafeUTF7Encoding>true</EnableUnsafeUTF7Encoding>
		<InvariantGlobalization>true</InvariantGlobalization>
		<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
		<MetadataUpdaterSupport>true</MetadataUpdaterSupport>
		<UseSystemResourceKeys>true</UseSystemResourceKeys>
		<IlcDisableReflection >true</IlcDisableReflection>
.NET7的AOT的使用

C# 调用 C# 生成的 AOT

在本小节中,将使用 CsharpAot 项目调用 CsharpExport 生成的动态链接库。

把 CsharpExport.dll 复制到 CsharpAot 项目中,并配置 始终复制

.NET7的AOT的使用

在 CsharpAot 的 Native 中加上:

    [LibraryImport("CsharpExport.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.I4)]
    internalstaticpartial Int32 Add(Int32 a, Int32 b);
.NET7的AOT的使用

然后在代码中使用:

staticvoidMain()
    {
        var result = Native.Add(1, 2);
        Console.WriteLine($"1 + 2 = {result}");
        Console.ReadKey();
    }

在 Visual Studio 里启动 Debug 调试:

.NET7的AOT的使用

可以看到,是正常运行的。

接着,将 CsharpAot 项目发布为 AOT 后,再次执行:

.NET7的AOT的使用

可以看到,.NET AOT 调用 .NET AOT 的代码是没有问题的。文章来源地址https://www.toymoban.com/news/detail-440748.html

到了这里,关于.NET7的AOT的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • .Net6 .Net7 支持的 Windows 版本

    .NET 6 支持下列 Windows 版本: (OS) Version 体系结构 Windows 11 21H2 x64、Arm64 Windows 10 客户端 1607+ x64、x86、Arm64 Windows 客户端 7 SP1+、8.1 x64、x86 Windows Server 2012+ x64、x86 Windows Server 核心 2012+ x64、x86 Nano Server 1809+ X64 如果要在以下 Windows 版本上安装 .NET SDK 或运行时,则需要其他依赖项:

    2024年02月16日
    浏览(26)
  • WPF C# .NET7 基础学习

    学习视频地址:https://www.bilibili.com/video/BV1hx4y1G7C6?p=3vd_source=986db470823ebc16fe0b3d235addf050 开发工具:Visual Studio 2022 Community 基础框架:.Net 6.0 下载创建过程略 .Net和.Framework 区别是Net是依赖项,Framework是引用 1.定义一个命名空间, 最常用 不只包括using namespace,还用开头使用的usin

    2024年02月10日
    浏览(34)
  • Debian12安装.NET7 SDK

    Debian,作为最受欢迎的 Linux 发行版之一,于 2023 年 6 月 10 日正式发布了其最新版本 Debian 12,代号“Bookworm”。Debian 12 带来了许多新特性和改进,其中最引人注目的是 Linux 内核的升级,从之前的 5.10 LTS 升级到了 6.1。 这两天尝试了一下Debian12。准备配置一个开发环境,将各类

    2024年02月08日
    浏览(28)
  • 第1章 .Net7 Areas实现

    1 集成路由匹配模式 var builder = WebApplication . CreateBuilder ( args ); // Add services to the container. builder . Services . AddControllersWithViews (); var app = builder . Build (); // Configure the HTTP request pipeline. if (! app . Environment . IsDevelopment ()) {     app . UseExceptionHandler ( \\\"/Home/Error\\\" );     // The default HSTS va

    2024年02月03日
    浏览(33)
  • Linux安装Net7SDK运行Net项目

    1.安装sdk依赖环境 2.安装 SDK 1.选择发布到指定文件夹 2.将发布的 publish 文件夹打包成zip,并将zip上传到云服务器指定文件夹下 3.cd 到zip所在文件夹,解压 4.进入publish文件夹中,运行对应服务dll --urls :运行时指定IP和端口 “ output.log ” :控制台输出内容写入指定文件中 :设

    2023年04月25日
    浏览(41)
  • .Net初学 创建一个巨简单的.Net7 WebApi后端框架

    visual studio 2022 以下简称vs    Visual Studio安装指南_visual studio安装教程_技术人小柒的博客-CSDN博客 sqlserver 2022 以下简称mssql        SQL Server2022 Express和SSMS下载安装教程(超详细) (baidu.com) redis Redis下载安装图文教程(Windows版_超详细)_windows redis下载_Leeway啊樺的博客-CSDN博客

    2024年02月21日
    浏览(31)
  • Kestrel封装在WindowService中(.net5,.net6,.net7三个版本的介绍)

    在一些开发过程中,会在局域网内搭建webapi服务作为移动端的服务接口使用,但是每次实施人员要到客户现场安装iis等工具,还有一些web的配置,非常繁琐,所以想着把webapi封装到WindowService中,可以通过自定义的安装程序进行一键部署,岂不美哉! 这篇文章主要是记录如何

    2024年02月08日
    浏览(27)
  • 怎么去除视频里的背景音乐?其实非常简单!

    如何去除视频背景音乐?在视频处理中,有时我们需要从视频中提取声音并进行处理,而不仅仅是简单地去除整个背景音乐。我们可能需要有选择性地去除人声或背景音乐。这个处理过程对于选用合适的工具至关重要。在本文中,我将分享两种可用于去除视频背景音乐的工具

    2024年02月14日
    浏览(33)
  • .NET Native AOT的静态库与动态库

    .NET不仅可以使用 C静态库与动态库,也可以将.NET实现的函数导出为C静态库与动态库。在没有Native Aot之前,.NET只能通过P/Invoke享受C/C++生态,而在Native Aot之后,不仅可以享受这些生态,还可以开发SDK供其他语言调用。 .NET Native AOT的NativeLib参数用于指定本机库的类型。在.NET

    2024年02月16日
    浏览(26)
  • .Net 7 Native AOT 单文件 无依赖 跨平台

    2022.11.18 Native AOT 正式发布,不再是 实验性项目。 .Net 7 Console App WebApi 使用PublishAOT = true,直接编译 成exe,无rutime依赖,智能裁剪,体积小,启动快。 环境: 1.更新VS2022 到最新版本(支持.net 7) 2.VS2022 安装 使用C++ 桌面开发   踩坑: 1.程序里一些 没有应用到的 方法会被裁剪

    2024年02月04日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包