Native AOT 必须通过 dotnet publish 生成,因依赖 RID 解析、IL 裁剪、元数据分析及后端代码生成等发布阶段流程;dotnet build 仅产出 IL,即使加 /p:PublishAot=true 也无效。

Native AOT 不是“编译开关”,而是发布阶段的跨平台原生代码生成行为;直接跑 dotnet build 永远得不到 AOT 二进制,必须用 dotnet publish 并带齐关键参数,否则静默失败或报错。
为什么 dotnet build 不能生成 AOT 二进制
AOT 编译依赖完整的发布流水线:运行时标识符(RID)解析、IL 裁剪、元数据可达性分析、LLVM 或 CoreRT 后端代码生成——这些全在 dotnet publish 阶段触发。dotnet build 只产出 IL 和中间产物,即使加了 /p:PublishAot=true 也无效。
- 常见错误现象:
MSB4057: The target "PublishAot" does not exist in the project.或构建成功但输出目录里只有.dll,没有原生可执行文件 - 根本原因:项目 SDK 不是
Microsoft.NET.Sdk(比如用了Microsoft.NET.Sdk.Web),dotnet publish会直接忽略PublishAot - 验证方式:检查
.csproj第一行是否为<Project Sdk="Microsoft.NET.Sdk">;如果不是,改掉并删掉所有<FrameworkReference>
dotnet publish 必须带的三个硬性参数
缺一不可,少一个就中断或降级为普通发布。
-
-r win-x64(或linux-x64、osx-arm64):RID 不能写any,不能省略。AOT 是“为某架构生成机器码”,没 RID 就没目标 -
--self-contained true:AOT 二进制必须自包含运行时逻辑(已内联),不支持--no-self-contained模式 -
/p:PublishAot=true:显式启用 AOT 流水线;--aot是简写,但推荐用完整属性名,避免和旧版混淆
正确命令示例:dotnet publish -c Release -r linux-x64 --self-contained true /p:PublishAot=true
System.Text.Json 和 HttpClient 在 AOT 下必踩的坑
AOT 静态分析无法推导运行时才决定的类型(如 JsonSerializer.Deserialize<T>(string) 中的 T),默认会裁剪掉反射路径,导致 MissingMethodException 或空对象。
- 禁止用
System.Net.Http.Json扩展方法(如PostAsJsonAsync),它们内部依赖反射序列化器,AOT 下不可达 - 必须改用
System.Text.Json.SourceGeneration:定义[JsonSerializable]上下文类,并在 DI 或手动构造时传入JsonSerializerOptions实例 - HttpClient 构造器可能被裁剪:在
.csproj中加<TrimmerRootAssembly Include="System.Net.Http" />,或确保构造逻辑出现在主入口可达路径中
调试符号、LLVM 和裁剪配置的实际影响
生成的二进制默认 strip 掉调试信息,且 Windows/macOS/Linux 对底层 C++ 工具链有强依赖。
- 想 attach 调试?加
--strip-symbols false,否则.pdb或.dwarf文件不会生成 - Windows 报 “LLVM not found”?不是 .NET SDK 问题,是系统缺 clang++:下载 LLVM 官方包,把
bin/加进 PATH -
/p:PublishTrimmed=true建议开启,但需配合<TrimMode>partial</TrimMode>:全量裁剪(link)会误杀泛型实例,partial 更安全
最易被忽略的一点:所有 NuGet 依赖(包括 Npgsql、Microsoft.Data.Sqlite、Microsoft.Extensions.*)版本必须 ≥8.0,低版本因反射调用未标注,会在 AOT 运行时报连接字符串解析失败——这个错误不会在编译期暴露,只在首次调用数据库时崩。


















