首页 > 其他分享 >dotnet7 aot编译实战

dotnet7 aot编译实战

时间:2022-09-23 14:45:52浏览次数:70  
标签:BouncyCastle FastGithub dotnet7 System 编译 aot output% fastgithub

0 起因

这段日子看到dotnet7-rc1发布,我对NativeAot功能比较感兴趣,如果aot成功,这意味了我们的dotnet程序在防破解的上直接指数级提高。我随手使用asp.netcore-7.0模板创建了一个默认的web程序,发现aot发布出来,web服务完全使用,这是之前那些preview版本做不到的。想到fastgithub本质上也是基于asp.netcore-6.0框架的项目,于是走上fastgithub的aot改造之路。

1 改造步骤

1.1 升级框架

将所有项目的TargetFramework值改为7.0,fastgithub使用Directory.Build.props,所以我只需要在Directory.Build.props文件修改一个地方,所有项目生效了。

1.2 升级nuget包

所有项目的nuget包进行升级,像有些是6.0.x版本的,如果有7.0.x-rc.x.x的更新包,就升级到最新rc版本。

1.3 json序列化

如果您的使用JsonSerializer序列化了内部未公开的类型,则需要改为JsonSerializerContext(源代码生成)方式,比如我在想序列化下面的EndPointItem类型的实例,需要如下改进:

private record EndPointItem(string Host, int Port);

[JsonSerializable(typeof(EndPointItem[]))]
[JsonSourceGenerationOptions(
    WriteIndented = true,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
private partial class EndPointItemsContext : JsonSerializerContext
{
}
 var utf8Json = JsonSerializer.SerializeToUtf8Bytes(endPointItems, EndPointItemsContext.Default.EndPointItemArray);

2 aot发布

我发布在vs上进行发布时有问题,我们需要在使用cli来发布,cli发布还能为我们提供更多的编译信息输出。

2.1 单文件的发布命令

set output=./publish
if exist "%output%" rd /S /Q "%output%"
dotnet publish -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained -r win-x64 -o "%output%/fastgithub_win-x64" ./FastGithub/FastGithub.csproj

aot编译之后也是单个文件,所以如果您的程序使用PublishSingleFile模式发布不能正常运行的话,就不用试着aot发布了。

2.2 aot发布的命令

set output=./publish
if exist "%output%" rd /S /Q "%output%"
dotnet publish -c Release /p:PublishAot=true /p:PublishTrimmed=true --self-contained -r win-x64 -o "%output%/fastgithub_win-x64" ./FastGithub/FastGithub.csproj

我们只需要把之前的PublishSingleFile改为PublishAot,他们两个不能同时设置为true。经过几分钟的满屏黄色警告之后,我们终于得到aot版本的40MB左右的fastgtihub.exe,迫不及待地运行了fastgithub.exe,不幸的是程序运行异常:

Unhandled Exception: System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
 ---> System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
 ---> System.NotSupportedException: 'Org.BouncyCastle.Security.DigestUtilities+DigestAlgorithm[]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
   at System.Reflection.Runtime.General.TypeUnifier.WithVerifiedTypeHandle(RuntimeArrayTypeInfo, RuntimeTypeInfo) + 0x5b
   at System.Array.InternalCreate(RuntimeType, Int32, Int32*, Int32*) + 0x5c
   at System.Array.CreateInstance(Type, Int32) + 0x46
   at System.RuntimeType.GetEnumValues() + 0x86
   at Org.BouncyCastle.Utilities.Enums.GetArbitraryValue(Type enumType) + 0xa
   at Org.BouncyCastle.Security.DigestUtilities..cctor() + 0x86

2.3 尝试解决BouncyCastle

BouncyCastle是用于生成ca证书和服务器证书的第三方库,在dotnet6时或以前,我们没有其它库可以完成这个功能。以上的异常大概是提示了DigestUtilities这个类型的某个内部私有类型被裁剪了,所以无法创建这个已裁剪掉类型的数组类型。我想到可以给项目的ItemGroup加上<TrimmerRootAssembly Include="BouncyCastle.Crypto" />,让这个程序集不要裁剪,然后再进行新一轮aot编译,不幸的是这次是编译时异常:

CVTRES : fatal error CVT1103: 无法读取文件 [D:\github\FastGithub\FastGithub\FastGithub.csproj]
LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 [D:\github\FastGithub\FastGithub\FastGithub.csproj]
C:\Program Files\dotnet\sdk\7.0.100-rc.1.22431.12\Sdks\Microsoft.DotNet.ILCompiler\build\Microsoft.NETCore.Native.targe
ts(349,5): error MSB3073: 命令“"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.34.31721\bin\Hostx
64\x64\link.exe" @"obj\Release\net7.0\win-x64\native\link.rsp"”已退出,代码为 1123。 [D:\github\FastGithub\FastGithub\FastGithu
b.csproj]

2.4 移除BouncyCastle

迫于无奈,我们必须移除对BouncyCastle的依赖,转为使用基础库来实现证书生成,这方面几乎没有任何可以查到有帮助的资料,我花了整整一天来改造,感兴趣证书生成的同学,可以参考CertGenerator.cs。去掉BouncyCastle之后再aot发布,程序可以运行起来了,没有任何异常,但是发现程序没有拦截任何流量。

2.5 查找程序不干活的原因

由于没有任何的异常输出,咱也不知道是啥情况,现在使用debug模式继续aot发布,然后运行fastgithub.exe,在vs附加到fastgithub进程,下断点分析。经过一路跟踪,我发现如下一个分支,总是进入return逻辑:

var domain = question.Name;
if (this.fastGithubConfig.IsMatch(question.Name.ToString()) == false)
{
    return;
}

我想看看fastGithubConfig现在是什么值,为什么总是不匹配,但是经过aot之后,无法发现fastGithubConfig这个局部变量,而函数内的变量,也不再是crl类型,而是一种为调试而存在的代理类型一样,可看的信息也很少。
于是我加入大量的log,通过log看看fastGithubConfig是什么值,最后发现是配置绑定到Options的字典类型属性时,绑定不成功(但也没有任何异常或日志)。

2.6 解决配置绑定到字典的问题

这个问题咱实在不知道怎么解决,那就github上发起问题吧:services.Configure(configuration) failure at PublishAot,果然回复很积极,告诉咱们目前可以在任意调用的函数加上[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Dictionary<string, DomainConfig>))]。经过这么修改之后,配置绑定到Options生效了。

3 后续

经过这么一个实际项目aot之后,我对aot有了初步的了解,个人觉得aot基本可以用小型程序的发布,期待到dotnet8之后,NativeAot变成没有坑。

标签:BouncyCastle,FastGithub,dotnet7,System,编译,aot,output%,fastgithub
From: https://www.cnblogs.com/kewei/p/16722674.html

相关文章

  • 高级编译器设计与实现 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1YiqZ0BN4H1hWeuM3M7Tt_Q点击这里获取提取码 ......
  • Windows下编译freeglut库
    背景glut库自从2000年之后就没更新了,freeglut库一般是只提供源代码,不提供预编译文件如果在Linux下使用,可以直接用install安装OpenGL开发环境。而在Windows则需要自行编译......
  • Android编译选项eng、user、userdebug的区别
    Android编译选项eng、user、userdebug的区别https://www.xuebuyuan.com/1408769.htmlAndroid编译选项中eng、user、user-debug主要区别https://blog.csdn.net/yanghanxing......
  • 脚本二进制编译安装Mysql
    mysql二进制安装脚本部署目录mysql二进制安装脚本部署单实例使用函数的单实例使用函数的单实例或者多实例单实例[root@localhost~]#mkdirmysql//创建存......
  • dll、lib编译与加载
    1.动态库的引用1.指定附加包含目录(.h文件)//在代码中可以直接指定目录,如#include"..\\..\\pthreads_w32\\Pre-built.2\\include\\pthread.h"2.指定附加库目录(.lib......
  • Python3交叉编译步骤(二)-三方库的交叉编译
    一.项目场景在cortex-A9主板上运行python3,能够使用常用的三方库二.配置主机环境:ubuntu-18.04-x86_64(虚拟机)交叉编译链:arm-linux-gnueabihf-gcc开发板:cortex-A9(armv7l)三.......
  • Pycharm的安装并且连接已有的Python环境实现自由编译(附中文配置)|并通过Pycharm实现增加
    Python环境的配置 通过python的官方网站:python.org即可进入python的官网-->选择Downloads即可进入选择版本的界面,在界面中选择自己想要下载的版本即可,下载好之后在安装界......
  • C#教程 - 编译器(Compile)
    更新记录转载请注明出处:2022年9月22日发布。2022年9月10日从笔记迁移到博客。编译器的类型csc//.NETFrameworkmsc//Monodotnet//.NetCoreC#......
  • 编译原理:运行时机制
    在语义分析之后,编译过程就开始进入了中后端。经过前端阶段的处理分析,编译器已经充分理解了源代码的含义,准备好把前端处理的结果(带有标注信息的AST、符号表)翻译成目标代码......
  • 浅谈汇编器、编译器、解释器和虚拟机
    1、汇编器:将汇编语言翻译成机器语言 2、编译器:将高级语言翻译成汇编语言,再由汇编器去处理 3、解释器:随着时间的推移,一种新的编程方式兴起了。一种被称为“解释器”的......