如何让库实现与本地AOT编译的兼容性?
摘要:原文 | Eric Erhardt 翻译 | 郑子铭 本机 AOT 是一种令人兴奋的发布 .NET 应用程序的新方法。多年来,我们听到了 .NET 开发人员的反馈,他们希望他们的应用程序比使用 .NET 构建的传统独立应用程序启动更快、使用
原文 | Eric Erhardt
翻译 | 郑子铭
本机 AOT 是一种令人兴奋的发布 .NET 应用程序的新方法。多年来,我们听到了 .NET 开发人员的反馈,他们希望他们的应用程序比使用 .NET 构建的传统独立应用程序启动更快、使用更少的内存并且磁盘大小更小。从 .NET 7 开始,我们添加了对将控制台应用程序发布到本机 AOT 的支持,并在 .NET 8 中继续将此功能引入 ASP.NET Core API 应用程序。
但这个旅程还没有完成。下一步是让更多令人难以置信的 .NET 生态系统能够在本机 AOT 应用程序中使用。并非所有 .NET 代码都可以在本机 AOT 应用程序中使用。可以使用的 .NET API 存在限制。要获取这些限制的完整列表,请参阅本机 AOT 部署文档,但以下是常见限制的简短列表:
该代码必须是修剪兼容的。
没有程序集的动态加载。
可以使用反射,但不支持步行类型图(就像基于反射的序列化器所做的那样)。
运行时不会生成代码,例如 System.Reflection.Emit。
API 在幕后要做什么并不总是显而易见的,因此很难判断哪些 API 可以安全使用,哪些 API 可能会在本机 AOT 应用程序中被破坏。为了解决这个问题,.NET 提供了分析工具,一旦针对 AOT 发布了应用程序,API 可能无法正常工作时,这些分析工具就会向您发出警报。这些工具对于制作与本机 AOT 良好配合的应用程序和库至关重要。
在这篇文章中,我将讨论一些使 .NET 库与本机 AOT 兼容的技巧和策略。许多库不使用有问题的模式并且可以正常工作。其他库已更新为兼容并准备好在 AOT 应用程序中使用。我将使用这些作为案例研究,重点介绍我们在更新 AOT 库时看到的一些常见情况。
警告
最重要的是要知道,.NET 有一组静态分析工具,当它看到经过修剪或本机 AOT 应用程序中可能有问题的代码时,它们会发出警告。这些警告是告诉您什么是有效的、什么是无效的指南。 .NET中修剪和AOT的主要原则是:
如果应用程序在针对 AOT 发布时没有警告,则在 AOT 后它的行为将与没有 AOT 时的行为相同。
这是一个大胆的声明,但我们相信这是获得可接受的开发体验的方法。我们过去尝试过采取大部分有效的方法,但直到您发布应用程序并执行它之后您才会知道。开发人员多次对这些方法感到失望。您需要在发布后执行应用程序中的每个代码路径,这很多时候是不可行的。我不希望任何开发人员经历在将应用程序部署到生产环境后发现它不起作用的情况。
请注意,该原则没有说明应用程序在发布期间确实出现警告时会发生什么情况。它可能有效,也可能无效。没有一种静态可验证的方法来确定会发生什么。在处理这些警告时记住这一点很重要。分析工具发现一些代码无法保证在发布后能够正常工作。发生这种情况时,它会发出警告,告诉您无法保证。
到目前为止,很明显这些警告很重要。我们需要关注他们。
在某些情况下,静态分析工具无法保证某些特定代码能够工作,但在分析自己之后,您决定它能够工作。对于这些情况,可以抑制警告。然而,如果没有确凿的证据,就不应该这样做。禁止对 99% 的时间都有效的代码发出警告违反了上述主要原则。如果应用程序以达到这 1% 情况的方式使用您的库,并且在发布后中断,则会降低没有警告意味着应用程序正常运行的承诺。
分析 .NET 库
我确信你在想“好吧,你说服了我。警告很重要,但我如何获得它们?”。有两种方法可以获取图书馆的警告。
罗斯林分析仪
这些分析仪的工作方式与任何其他 Roslyn 分析仪一样。一旦启用,它们会在构建过程中产生警告,并且您会在您最喜欢的编辑器中看到波形曲线。这些非常适合快速提醒您出现问题,有些甚至还附带代码修复程序。
使用 .NET 8+ SDK 时,您可以在库的 .csproj 中(或在存储库中所有项目的 Directory.Build.props 文件中)设置以下内容:
<PropertyGroup>
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
</PropertyGroup>
这一属性将启用三个底层 Roslyn 分析器:
启用修剪分析器
启用单文件分析器
启用Aot分析器
您可能会注意到上述 MSBuild 设置中的 Condition。这是必要的,因为 Roslyn 分析器根据您的库调用的 API 上的属性进行工作。
