解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
|
# NewLife.Core AOT 兼容性现状与边界
> 基线:v12|评估方å¼ï¼š**NativeAOT 真实编译 + è¿è¡Œå®žæµ‹**(win-x64,.NET 10)|冒烟工程:`AotSmoke/`
---
## 1. 现状摘è¦
- **æ ¸å¿ƒé“¾è·¯å®žæµ‹å…¨é€š**:31 场景冒烟 JIT/AOT åŒé€šï¼ˆÂ§2.1),覆盖日志ã€ç½‘络(TCP/HTTP/WebSocket)ã€åºåˆ—化(JSON/Binary/Span/STJ æºç”Ÿæˆä¸Šä¸‹æ–‡ï¼‰ã€é…ç½®ã€IoCã€Http 控制器ã€CsvDb/DbTableã€å射泛型入å£ä¿ç•™ã€å¹³å°æŽ¢æµ‹ï¼ˆRuntime/MachineInfo/PathHelper/ProcessHelper)ã€å¤šè¯è¨€è¯è¡¨æŸ¥è¡¨ä¸Žå…¨éƒ¨å†…ç½®è¯è¨€ã€‚
- **æ”¯æŒæ–¹å¼**:主链路以「泛型/Type å…¥å£çš„ä¿ç•™æ³¨è§£ + æºç”Ÿæˆå™¨é™æ€è¡¨ã€è¾¾æˆâ€”—生æˆå™¨æ‰¿æŽ¥ DI 注册ã€Json æˆå‘˜è®¿é—®ã€é…置绑定ã€Http 分å‘å››æ¡é€šé“;生æˆç‰©æœªè¦†ç›–的场景自动回退原å射路径,è¿è¡Œè¯ä¹‰ä¸å˜ï¼ˆÂ§4)。
- **已知边界**:动æ€èƒ½åŠ›ï¼ˆè„šæœ¬/æ’ä»¶/DLR/表达å¼ç¼–è¯‘ï¼‰è®¾è®¡æ€§ä¸æ”¯æŒï¼›éƒ¨åˆ†åªèƒ½ç» `Object`/è¿è¡Œæ—¶ç±»åž‹è¿›å…¥çš„æˆå‘˜æžšä¸¾è·¯å¾„æ— æ³•é™æ€è¡¨è¾¾ä¿ç•™è¦æ±‚(§5 æ”¶å£è®°å½•)。
- **告è¦é¢å·²æ”¶æ•›**:编译期分æžå™¨ä¸Žå‘布期 ILC å‡ **0 æ¡**告è¦ï¼ˆÂ§2.2)。动æ€èƒ½åŠ›ä»¥å£°æ˜Žä¸Žå®ˆå«æ‰¿æŽ¥ï¼Œèƒ½é™æ€è¡¨è¾¾çš„ä¸€å¾‹ä¼ å¯¼ã€‚
---
## 2. 实测数æ®
### 2.1 è¿è¡ŒæœŸï¼š31 场景冒烟(JIT/AOT åŒé€šï¼‰
| # | 场景 | # | 场景 |
|---|------|---|------|
| 1 | åŸºç¡€ç±»åž‹è½¬æ¢ Utility | 13 | ObjectContainer æœåŠ¡è§£æž |
| 2 | ç±»åž‹è¢«é™æ€å¼•用时 `Type.GetTypeEx` | 14 | 动æ€èƒ½åŠ›å®ˆå« `PluginHelper`(AOT 下抛明确异常) |
| 3 | 日志 XTrace æŽ§åˆ¶å° | 15 | æºç”Ÿæˆå™¨æœåŠ¡å·¥åŽ‚ |
| 4 | 日志 TextFileLog 文件 | 16 | æºç”Ÿæˆå™¨ Json æˆå‘˜è®¿é—® |
| 5 | `ReceivedEventArgs.Rent` 直接调用 | 17 | æºç”Ÿæˆå™¨é…置绑定 |
| 6 | é…ç½® JsonConfigProvider 往返 | 18 | Http 异æ¥å§”托返回值 |
| 7 | JSON JsonHelper 往返 | 19 | Http æŽ§åˆ¶å™¨å¼‚æ¥æ“作方法 |
| 8 | SpanSerializer 往返 | 20 | Http æŽ§åˆ¶å™¨é™æ€åˆ†å‘ |
| 9 | Binary 写入 | 21 | Http 陿€åˆ†å‘优先级 |
| 10 | NetServer/NetClient TCP+SrmpCodec 回环 | 22 | CsvDb 读写往返 |
| 11 | HttpServer+ApiHttpClient GET(å«å¯¹è±¡ååºåˆ—化) | 23 | DbTable 模型读写往返 |
| 12 | WebSocket 文本回显 | 24 | SystemJson 上下文é€ä¼ |
| | | 25 | Reflect 泛型入å£ä¿ç•™ï¼ˆ`GetPropertyEx<T>`) |
| 26 | è¿è¡Œæ—¶å¹³å°æŽ¢æµ‹ Runtime | 27 | æœºå™¨ä¿¡æ¯ MachineInfo å¹³å°åˆ†æ”¯ |
| 28 | 临时路径与文件IO PathHelper | 29 | è¿›ç¨‹ä¿¡æ¯ ProcessHelper |
| 30 | 多è¯è¨€ Localizationï¼ˆå« XException / è¿è¡Œæ—¶æ³¨å†Œï¼‰ | 31 | 多è¯è¨€å…¨éƒ¨å†…ç½®è¯è¨€è¡¨åœ¨ AOT 下å¯ç”¨ï¼ˆ31 ç§ï¼‰ |
> AOT 判真:原生å‘å¸ƒä»¶å…¥å£ `Assembly.Location` 为空,而 JIT 基线为ç£ç›˜è·¯å¾„ï¼›å› å†’çƒŸå·¥ç¨‹å›ºå®šâ€œä¸¥æ ¼ AOT å§¿æ€â€ï¼Œä¸¤ç§è¿è¡Œçš„ `IsDynamicCodeSupported` å‡ä¸º False,该值ä¸ä½œåˆ¤åˆ«ä¾æ®ã€‚
### 2.2 编译期:分æžå™¨ä¸Ž ILC 告è¦
- **当å‰å‡ä¸º 0 æ¡**:`IsAotCompatible` 已在 csproj 对 net8.0+ï¼ˆå« `-windows` å½¢æ€ï¼‰å¸¸é©»å¯ç”¨ï¼Œåˆ†æžå™¨å‘Šè¦ 0 æ¡ï¼ˆnet8.0/net9.0/net10.0 åŠå¯¹åº” `-windows` å½¢æ€å®žæµ‹ï¼‰ï¼›AOT å‘布的 ILC å‘Šè¦ 0 æ¡ï¼ˆå†’çƒŸå·¥ç¨‹å®žæµ‹ï¼‰ã€‚åŸºçº¿ï¼ˆæ”¹é€ å‰ï¼‰ä¸º 164 æ¡å”¯ä¸€å‘Šè¦ã€‚
- é—留告è¦çš„三类å«ä¹‰ä¸Žå¤„置方å¼ï¼š
- **动æ€èƒ½åŠ›**(IL3050/IL2026/IL3000ï¼‰ï¼šè®¾è®¡æ€§ä¸æ”¯æŒ → 按 §5 用 `RequiresDynamicCode`/`RequiresUnreferencedCode` 声明 + è¿è¡ŒæœŸå®ˆå«ï¼Œæˆ–在边界方法上显å¼å£°æ˜Žè£å‰ªè¯ä¹‰ï¼›
- **宽é¢åå°„å…¥å£**(IL2075/IL2070/IL2057):è¿è¡Œæ—¶ç±»åž‹æ— æ³•é™æ€è¡¨è¾¾ → æä¾›æ³›åž‹å…¥å£æ‰¿è½½ä¿ç•™è¦æ±‚ï¼Œéžæ³›åž‹é‡è½½æ˜¾å¼å£°æ˜Žï¼›
- **ä¼ å¯¼æç¤º**(IL2067/IL2091/IL2095ï¼‰ï¼šèƒ½é™æ€è¡¨è¾¾çš„通过泛型入å£/æ³¨è§£ä¼ å¯¼ï¼Œè°ƒç”¨æ–¹æŒ‰æç¤ºä¿ç•™å…ƒæ•°æ®å³å¯ã€‚
- 说明:ILC åªè®¤ `UnconditionalSuppressMessage`,**ä¸è®¤ `#pragma warning disable`**——库内声明一律用特性,æ‰èƒ½åŒæ—¶æ¶ˆæŽ‰åˆ†æžå™¨ä¸Žå‘布期告è¦ã€‚
- Android ä¿ç•™å£°æ˜Žçš„ç›®æ ‡å·®å¼‚ï¼ˆIL2035):`MachineInfo.ReadDeviceInfo` 与 `GetAndroidBuildVersion` 用 `DynamicDependency(..., "Mono.Android")` 为 Android 消费端ä¿ç•™æˆå‘˜ï¼›æ¡Œé¢ / Linux / macOS ç›®æ ‡æ²¡æœ‰ `Mono.Android` 程åºé›†ï¼ŒILC å‘布时会报“Unresolved assemblyâ€è¯¯æŠ¥ã€‚两处å‡ä»¥æˆå‘˜çº§ `UnconditionalSuppressMessage("Trimming", "IL2035")` 抑制,ä¿ç•™å£°æ˜Žä¿æŒåŽŸæ ·ï¼ˆAndroid 消费端行为ä¸å˜ï¼‰ï¼Œå®žæµ‹ win-x64 / linux-x64 原生å‘布 0 æ¡ IL 告è¦ã€‚
---
## 3. 关键机制与生æˆå™¨ä½“ç³»
### 3.1 关键机制备忘
1. **`DynamicallyAccessedMembers` åªå¯¹ `Type`/`String` 傿•°ä¸Žæ³›åž‹å‚数生效**;放在 `Object`/`Task` ç‰å‚数上会被 ILC 直接忽略(IL2098ï¼‰ï¼Œå±žæ— æ•ˆæ³¨è§£ã€‚
2. **ä¿ç•™è¦æ±‚å¿…é¡»ç»ã€Œæ³›åž‹/Type å…¥å£ã€ä¼ 导**:`Load<T>`/`Bind<T>`/`Save<T>`ã€`CsvDb<T>`ã€`DbTable.WriteModels<T>`ã€`MapController<T>` ç‰å…¥å£æŒ‰ä¸‹å‘è¦æ±‚ï¼›`Object` 傿•°å…¥å£ï¼ˆå¦‚ç›´è°ƒ `MapTo`)表达ä¸äº†ï¼Œåªèƒ½ç”±å…¶ä»–å…¥å£å…ˆä¿ç•™ï¼ˆÂ§5)。
- åå°„é—¨é¢åŒç†ï¼š`Reflect.GetPropertyEx<T>` / `GetMethodEx<T>` / `CreateInstance<T>` 把ä¿ç•™è¦æ±‚æ”¾åœ¨æ³›åž‹å‚æ•°ä¸Šï¼ˆ`typeof(T)` 调用点天然ä¿ç•™ï¼‰ï¼›å¯¹åº”çš„éžæ³›åž‹ `Type` é‡è½½ä¿æŒé›¶æ³¨è§£ï¼ˆ**ç»™å®½é¢ `Type` 傿•°åŠ æ³¨è§£ä¼šè®©å…¨åº“ 60+ 文件ã€300+ è°ƒç”¨ç‚¹å¼¥æ•£ä¼ å¯¼å‘Šè¦**),动æ€è¯ä¹‰åœ¨è¯¥å¤„显å¼å£°æ˜Žã€‚
3. **è¿è¡Œæ—¶æœªçŸ¥æ³›åž‹**用开放泛型ä¾èµ–声明覆盖全部实例化:`[DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(Task<>))]`(`TaskHelper.GetResult` 峿¤ä¾‹ï¼‰ã€‚低版本 TFM ç”± `Stub` ä¸çš„ `DynamicDependencyAttribute` 垫片补é½ã€‚
4. **动æ€èƒ½åŠ›ä¸å¯æ”¹é€ **:以 `RequiresDynamicCode`/`RequiresUnreferencedCode` 声明 + `RuntimeFeature.IsDynamicCodeSupported` 守å«ï¼Œè¿è¡ŒæœŸæŠ›æ˜Žç¡®å¼‚常而éžé™é»˜é”™ã€‚
### 3.2 生æˆå™¨ä½“ç³»ï¼ˆé™æ€åŒ–通é“)
| 生æˆå™¨ | æ‰¿æŽ¥é€šé“ | 生æˆç‰© |
|---|---|---|
| `ServiceRegistrarGenerator` | DI 注册(`AddTransient<TService,TImpl>` ç‰ï¼Œé™å”¯ä¸€å…¬å¼€æ— 傿ž„é€ ï¼‰ | `ServiceFactoryTable` 工厂注册 |
| `JsonSerializableGenerator` | `JsonHelper` 泛型/Type å…¥å£çš„æˆå‘˜è®¿é—® | `MemberAccessorTable` 读写委托 |
| `ConfigModelGenerator` | `Config<T>` åç±»é…置绑定 | `ConfigProvider.DataRetrieval` 绑定器 |
| `HttpControllerDispatchGenerator` | `MapController<T>` æŽ§åˆ¶å™¨åŠ¨ä½œåˆ†å‘ | `HttpDispatchTable` 方法å→强类型调用 |
- **éž AOT æ¡ä»¶ç¼–译**:生æˆç‰©åœ¨ JIT ä¸‹åŒæ ·ç”Ÿæ•ˆï¼ˆå…åå°„ã€å…表达å¼ç¼–译与暖机);生æˆå™¨ç¼ºå¸æˆ–未覆盖场景自动回退å射,è¯ä¹‰ä¸å˜ã€‚
- **å¯åŠ¨é¡ºåº**:生æˆç‰©ä»¥ `[ModuleInitializer]` æ³¨å†Œï¼Œå…ˆäºŽä»»ä½•é™æ€æž„é€ ï¼›åˆ†å‘å½¢æ€ä¸ºéšä¸»åŒ… `analyzers/dotnet/cs` 分å‘,下游零é…置。
- **新增通é“四件套**:è¿è¡ŒæœŸè¡¨ + 生æˆå™¨ + 生æˆç‰©å•测(`XUnitTest.SourceGenerator`)+ 冒烟"生æˆ/回退"åŒåœºæ™¯ã€‚
---
## 4. 下游使用指引
- **å¯ç”¨æ–¹å¼**:`<PublishAot>true</PublishAot>` 写在**应用工程**属性组内;**ä¸è¦**ç”¨å‘½ä»¤è¡Œå…¨å±€å±žæ€§ä¼ å…¥ï¼ˆ`-p:PublishAot=true` 会波åŠå¤š TFM ä¾èµ–项目的 net45 ç‰ç›®æ ‡ï¼ŒæŠ¥ `NETSDK1207`)。
- **IoC 注册(æºç”Ÿæˆå™¨ï¼Œè‡ªåŠ¨ç”Ÿæ•ˆï¼‰**:`container.AddTransient<TService, TImpl>()` / `AddSingleton<...>` ç‰æ‰©å±•æ–¹æ³•æ³¨å†Œè°ƒç”¨ç‚¹ä¼šè‡ªåŠ¨ç”ŸæˆæœåŠ¡å·¥åŽ‚å¹¶æ³¨å†Œè¿› `ServiceFactoryTable`(é™"å”¯ä¸€å…¬å¼€æ— å‚æž„é€ "的实现类型);è¿è¡ŒæœŸå…ˆæŸ¥è¡¨ã€æœªå‘½ä¸å†å›žé€€åå°„æž„é€ ã€‚ç”Ÿæˆå™¨éš `NewLife.Core` 包自动分å‘(`analyzers/dotnet/cs`ï¼‰ï¼Œæ— éœ€åº”ç”¨ä¾§é¢å¤–引包。
- **Json åºåˆ—化(æºç”Ÿæˆå™¨ï¼Œè‡ªåŠ¨ç”Ÿæ•ˆï¼‰**:类型ç»ç¼–译期已知泛型/`Type` å…¥å£è¿›å…¥ `JsonHelper`(`ToJson`/`ToJsonEntity<T>`/ååºåˆ—化泛型)时,æˆå‘˜è®¿é—®å™¨èµ° `MemberAccessorTable`,é¿å…对 `PropertyInfo` 的引用被è£å‰ªã€‚
- **System.Text.Json è¿è¡Œæ—¶ç±»åž‹è·¯å¾„(上下文é€ä¼ )**:`SystemJson` çš„ `Write(Object)`/`Read(json, Type)` ç»è¿è¡Œæ—¶ç±»åž‹è§£æžï¼›æŠŠåº”用的 `JsonSerializerContext` ä¼ å…¥æž„é€ å³å¯è®©è¿™äº›ç±»åž‹ç”±æºç”Ÿæˆå…ƒæ•°æ®è§£æžâ€”—`new SystemJson(MyContext.Default)`(å¯ä¼ 多个,未声明类型自动回退默认解æžå™¨ï¼‰ã€‚ä¸Šä¸‹æ–‡åªæä¾›æˆå‘˜å…ƒæ•°æ®ï¼Œå‘½åç–ç•¥ç‰è¡Œä¸ºä»¥ `SystemJson` 自身选项为准。
- **Type 傿•° API 的使用指引**:容器注册ã€`Config<T>`ã€`CsvDb<T>` ç‰ä¸»é“¾å·²ç”±ç”Ÿæˆå™¨ä¸Žæ³›åž‹å…¥å£è¦†ç›–;直接使用 `typeof(X).CreateInstance()`ã€`Reflect.GetPropertyEx/GetMethodEx`ã€`IReflect` 宽颿ˆå‘˜è®¿é—®ç‰è¿è¡Œæ—¶ç±»åž‹ API 时,元数æ®èƒ½å¦ä¿ç•™å–决于调用方——先用泛型入å£è§¦è¾¾ç›®æ ‡ç±»åž‹ï¼ˆå¦‚ `Load<T>`ã€`GetService<T>`ã€`Reflect.GetPropertyEx<T>`),或用 `DynamicDependency` 显å¼å£°æ˜Žä¿ç•™ã€‚
- **é…置绑定(æºç”Ÿæˆå™¨ + æ ‡å‡†å…¥å£ï¼‰**:é…置类继承 `Config<T>` åŽè‡ªåŠ¨æ³¨å†Œå…¥ `ConfigProvider.DataRetrieval`(绑定器编译期生æˆï¼‰ï¼›`Config<T>.Current` 与 `IConfigProvider.Load<T>()` å‡ç»æ³›åž‹å…¥å£ï¼ŒAOT 䏋坿£ç¡®ç»‘定;**åªæœ‰**显å¼ç”¨ `ConfigSetting`(`Object` 傿•°å…¥å£ï¼‰ç»‘定æ‰ä¾èµ–ä¿ç•™æ³¨è§£ï¼Œå»ºè®®æ”¹ç”¨æ³›åž‹å…¥å£æˆ– `provider.Load<T>()`。
- **æŽ§åˆ¶å™¨é™æ€åˆ†å‘(æºç”Ÿæˆå™¨ï¼Œè‡ªåŠ¨ç”Ÿæ•ˆï¼‰**:生æˆå™¨æ‰«æ `MapController<T>` 注册调用点,为控制器生æˆ"方法å → 强类型调用"委托并注册进 `HttpDispatchTable`ï¼›`ControllerHandler` 命ä¸åˆ†å‘表å³é›¶å射调用;未命ä¸ï¼ˆå¦‚手工装é…的探针控制器)自动回退原å射路径。
- **é‡åˆ° "䏿”¯æŒ AOT/è£å‰ª" è¦å‘Š**:1) 确认该 API 是å¦åœ¨ä¸»é“¾è·¯ï¼›2) 需è¦å°±ç”¨æ³›åž‹å…¥å£/ä¿ç•™æ³¨è§£å¤„ç†ï¼›3) 动æ€èƒ½åŠ› APIï¼ˆè„šæœ¬ã€æ’ä»¶ã€è¡¨è¾¾å¼ç¼–译)在 AOT ä¸‹å¿…é¡»å…³é—æˆ–è§„é¿ï¼ˆ`RuntimeFeature.IsDynamicCodeSupported`)。
- **é‡åˆ° `RequiresDynamicCode` è¦å‘Š**:说明调用路径å«è¿è¡Œæ—¶ç”Ÿæˆä»£ç 能力,AOT 下è¿è¡Œåˆ°ä¼šæŠ›å¼‚å¸¸ï¼›æŒ‰åœºæ™¯æ”¹ç”¨é™æ€è·¯å¾„æˆ–åŠ å¼€å…³åˆ¤æ–。
- **排障æç¤º**:`IsDynamicCodeSupported=False` 表示真 AOTï¼›`Assembly.Location` 为空是 AOT æ£å¸¸è¡¨çŽ°ï¼Œä¸è¦ç”¨å®ƒåˆ¤æ–目录。
---
## 5. 已知边界与收å£è®°å½•(åªå¢žä¸åˆ )
| 项 | ä½ç½® | 现状与ç†ç”± |
|---|---|---|
| 实例æˆå‘˜çš„è¿è¡Œæ—¶æžšä¸¾ï¼ˆ`IReflect` æ‹·è´/å¡«å……ç‰å®½é¢ç›®æ ‡ï¼‰ | `Reflection/IReflect.cs` | ç» `Object` 傿•°è¿›å…¥ï¼Œè¿è¡Œæ—¶æ‰çŸ¥ç›®æ ‡æ˜¯ä»»æ„类型,**æ— æ³•é™æ€è¡¨è¾¾ä¿ç•™è¦æ±‚**;泛型入å£ï¼ˆ`Copy<T>` ç‰ï¼‰å·²è¦†ç›–主场景;边界方法以特性显å¼å£°æ˜Žè£å‰ªè¯ä¹‰ã€‚ |
| 程åºé›†ä¸Žç±»åž‹å‘现é¢ï¼ˆ`AssemblyX` 全部方法ã€`PluginHelper.LoadPlugin`) | `Reflection/AssemblyX.cs`ã€`Web/PluginHelper.cs` | æ’ä»¶å‘现是 AOT è®¾è®¡æ€§ä¸æ”¯æŒï¼ˆ`PluginHelper.LoadPlugin` å·²åŠ `RequiresDynamicCode`/`RequiresUnreferencedCode`);`AssemblyX` 按方法声明动æ€åŠ è½½è¯ä¹‰ï¼ŒAOT 下按空值é™çº§ã€‚ |
| Windows ç³»ç»Ÿä¿¡æ¯æŽ¢æµ‹ï¼ˆWMI/注册表/COM/性能计数器) | `Common/MachineInfo*.cs` | ä¾èµ– COM 与è¿è¡Œæ—¶å射绑定,AOT 下ä¸å—支æŒï¼›æŽ¢æµ‹å¤±è´¥æŒ‰ç©ºå€¼é™çº§ï¼Œä¸å‚与业务主链;å¯é™æ€è¡¨è¾¾çš„(`Marshal.SizeOf<T>`)已改用泛型入å£ã€‚ |
| 动æ€è¯ä¹‰è¾¹ç•Œï¼ˆDLR åŠ¨æ€æˆå‘˜ã€è¿è¡Œæ—¶ç‰¹æ€§è¯»å–ã€æœåŠ¡å®šä½ã€è°ƒè¯•用内å˜è¯»å–ç‰ï¼‰ | `Reflection/DynamicInternal.cs`ã€`AttributeX.cs`ã€`Model/ObjectContainer.cs`ã€`Extension/ProcessHelper.cs` ç‰ | è¯ä¹‰æœ¬èº«å³è¿è¡Œæ—¶ç±»åž‹ï¼Œé€æ–¹æ³•显å¼å£°æ˜Žè£å‰ªè¯ä¹‰ï¼ˆå«æ›¿ä»£å…¥å£æŒ‡å¼•),ä¸é€ç‚¹æ”¹é€ 。 |
| 控制器分å‘傿•°ç»‘定(`ref/out/params`/`ValueTask` ç‰ï¼‰ | `HttpControllerDispatchGenerator` | 生æˆå™¨ä¸»åŠ¨è·³è¿‡æ— æ³•å®‰å…¨ç”Ÿæˆçš„ç¾å(回退å射),未求穷尽。 |
| 低版本 TFM 的注解元数æ®ä½“积 | `Stub/CodeAnalysisAttributes.cs` | 实测注解使用点在æ¯ä¸ªä½Žç‰ˆæœ¬ DLL 约å 9.5~10 KB(以 `UnconditionalSuppressMessage` çš„ä¸æ–‡è¯´æ˜Žä¸²ä¸ºä¸»ï¼ŒRoslyn å·²å…±äº«ç›¸åŒ blob);已用 `[Conditional]` 镜åƒç¬¦å·åœ¨ä½Žç‰ˆæœ¬ç¼–译期整体消除(net45 −10,752 Bã€netstandard2.0 −10,240 Bã€netcoreapp3.1 −10,752 Bï¼›net6.0 ä»… RDC 一处)。注解类型定义本身(约 4 KB)ä¿ç•™â€”—编译期必须å¯è§£æžã€‚边界:低版本资产ä¸å†æºå¸¦è¿™äº›æ³¨è§£ï¼Œé“¾æŽ¥å™¨åœºæ™¯å¦‚需æ¢å¤ï¼Œåˆ 除对应 Conditional 行å³å¯ã€‚ |
---
## 6. å¤çŽ°æ–¹æ³•
```powershell
# 1) 分æžå™¨å…¨é‡è¦å‘Šï¼ˆåº“自身编译,期望 0 æ¡ï¼›IsAotCompatible å·²éš csproj 对 net8.0+ 常驻å¯ç”¨ï¼‰
dotnet build NewLife.Core\NewLife.Core.csproj -f net10.0 -c Release
# 2) 冒烟实测(31 场景工程;PublishAot 写在工程文件内)
dotnet run -c Release --project AotSmoke\AotSmoke.csproj # JIT 基线
dotnet publish AotSmoke\AotSmoke.csproj -c Release -r win-x64 -o out # NativeAOT 真编译(期望 0 æ¡ ILC 告è¦ï¼‰
.\out\AotSmoke.exe # AOT è¿è¡Œï¼Œé€åœºæ™¯ PASS/FAILï¼ˆéž 0 退出ç å³å¤±è´¥ï¼‰
```
> CI 防回归:`.github/workflows/aot.yml` + `.github/workflows/test.yml`(push/PR + 人工手动触å‘ï¼Œæ— å¤œé—´ä»»åŠ¡ï¼‰â€”â€” 分æžå™¨ 0 告è¦ç¡¬çº¦æŸï¼ˆé˜»æ–)+ NativeAOT 冒烟矩阵(win-x64 / linux-x64 / linux-arm64 阻æ–é—¨ç¦ï¼›win-arm64ã€osx åŒæž¶æž„ã€musl 容器观察期,稳定åŽé€é¡¹è½¬é˜»æ–);边缘 RID(win-x86 / linux-arm)与 LA64(linux-loongarch64,loong64 容器 + QEMU 仿真)已由原夜间 `edge.yml` å¹¶å…¥å¸¸è§„ä»»åŠ¡ï¼Œå…¶ä¸ LA64 çš„å•æµ‹ä¸Ž AOT 冒烟自 2026-10-17 èµ·å‡ä¸ºè§‚察期(仅人工 `workflow_dispatch` 触å‘ã€å¤±è´¥ä¸é˜»å¡žï¼‰ã€‚指令集矩阵(linux-riscv64 / linux-s390x)自 2026-10-18 起接入:push/PR åªè·‘ smoke å集(`XUnitTest.Buffers/Algorithms/Collections`,å—节åºä¸Žä½è¿ç®—确定性用例),全é‡ä»…人工 `workflow_dispatch` 触å‘ï¼Œå‡ `continue-on-error` ä¸é˜»å¡žï¼ˆppc64le å› QEMU 下 .NET 转æ¢ç¼ºé™·æŽ’é™¤ï¼Œè§ Â§7.3)。
---
## 7. 多 RID 支æŒçŸ©é˜µä¸Ž CI
> ç›®æ ‡ï¼šwin-x64 / linux-x64 / linux-arm64 啿µ‹å¿…选(阻æ–é—¨ç¦ï¼‰ï¼›linux-la64 啿µ‹ä¸Ž AOT 冒烟为观察期(仅人工触å‘ã€å¤±è´¥ä¸é˜»å¡žï¼ŒQEMU ä¸‹æ•´å¥—å•æµ‹ä»¥å°æ—¶è®¡ï¼‰ï¼Œæ‰©å±• win-arm64ã€linux-muslã€osx åŒæž¶æž„与边缘 RID(win-x86ã€linux-arm,观察期容错);linux-riscv64 / linux-s390x 按 LA64 的容器化 QEMU é…æ–¹æŽ¥å…¥ï¼ˆè§‚察期,push/PR è·‘ smoke å集ã€å…¨é‡äººå·¥è§¦å‘);ppc64le å› ä»¿çœŸå±‚é™åˆ¶æŽ’é™¤ï¼ˆè§ Â§7.3)。
> å‰æï¼š**NativeAOT å®˜æ–¹ä¸æ”¯æŒè·¨ OS 编译**(Windows→Linux 需 WSL/VM),支æŒåŒ OS 内 x64↔arm64 交å‰ï¼›å› æ¤æ¯ä¸ª RID å‡ä½¿ç”¨åŽŸç”Ÿ runner å‘布è¿è¡Œã€‚
### 7.1 覆盖分层
| 层级 | ç›®æ ‡ RID | 啿µ‹ | AOT 冒烟 | runner / 载体 | çŠ¶æ€ |
|---|---|---|---|---|---|
| T1 ä¸»æµ | win-x64 | ✔(既有 10 个 job) | ✔ é˜»æ– | windows-latest | é—¨ç¦ |
| T1 ä¸»æµ | win-arm64 | ✔ Core net8/net10 | ✔ | windows-11-arm(自带 ARM64 MSVC 工具链) | 观察期 |
| T1 ä¸»æµ | linux-x64 | ✔ Core åŒ TFM + Compat + æºç”Ÿæˆå™¨ | ✔ é˜»æ– | ubuntu-latest | é—¨ç¦ |
| T1 ä¸»æµ | linux-arm64 | ✔ Core net8/net10 | ✔ é˜»æ– | ubuntu-24.04-arm | é—¨ç¦ |
| T1 ä¸»æµ | linux-musl-x64 / arm64 | ✔ Core net10(alpine 容器) | ✔ | ubuntu(-arm) + alpine:3.20 容器 | 观察期 |
| T1 ä¸»æµ | osx-arm64 / osx-x64 | ✔ Core net8/net10 | ✔ | macos-latest / macos-15-intel(官方称å¯ç”¨è‡³ 2027-08) | 观察期 |
| T2 边缘 | win-x86 | — | ✔ | windows-latest 交å‰å‘布 | 观察期容错(aot.yml) |
| T2 边缘 | linux-arm(32 ä½ï¼‰ | — | 探索 | QEMU 容器 JIT 冒烟 + 交å‰å‘布å°è¯• | 观察期容错(aot.yml) |
| T2 边缘 | linux-riscv64 | ✔ smoke(push/PR)+ å…¨é‡ï¼ˆäººå·¥ï¼‰ | JIT 冒烟观察期 + å‘布探索 | docker + riscv64 容器(QEMU 用户æ€ï¼‰+ 社区 SDK(test.yml / aot.yml) | è§‚å¯ŸæœŸï¼ˆæœ¬åœ°å…¨é‡ 3573/0) |
| T2 边缘 | linux-s390x | ✔ smoke(push/PR)+ å…¨é‡ï¼ˆäººå·¥ï¼‰ | —(ILCompiler æ— s390x åŽç«¯ï¼‰ | docker + s390x 容器(QEMU 用户æ€ï¼‰+ Ubuntu `dotnet-runtime-10.0` | è§‚å¯ŸæœŸï¼ˆæœ¬åœ°å…¨é‡ 3573/0) |
| T3 LA64 | linux-loongarch64 | ✔ å…¨é‡ net10.0(观察期,人工触å‘) | JIT 冒烟观察期 + å‘布探索 | docker + loong64 容器(QEMU 用户æ€ï¼‰+ 龙芯 SDK(test.yml / aot.yml) | 观察期(手动触å‘,ä¸é˜»å¡žï¼‰ |
- **观察期约定**:win-x86 / linux-arm åŠ win-arm64 / osx / musl ç‰æœªè½¬æ£å¹³å° job 带 `continue-on-error`,连ç»ç¨³å®šå…¨ç»¿åŽé€é¡¹è½¬é˜»æ–é—¨ç¦ï¼›win-x64 / linux-x64 / linux-arm64 为阻æ–é—¨ç¦ï¼›LA64 çš„å•æµ‹ä¸Ž AOT 冒烟为观察期(`workflow_dispatch` 人工触å‘,push/PR ä¸å‚与ã€å¤±è´¥ä¸é˜»å¡žï¼‰ï¼›linux-riscv64 / s390x çš„ smoke 与全é‡åŒæ ·å¸¦ `continue-on-error`,全é‡ä»…人工触å‘,smoke 稳定åŽå†è¯„估是å¦è¿› push/PR é—¨ç¦ã€‚
- **测试并行度**:Windows/Linux CI 使用 `test.ci.runsettings`(4 çº¿ç¨‹ï¼ŒåŒ¹é… 4 vCPU runner);macOS 3 vCPU 使用专用 `test.ci.macos.runsettings`(3 线程)。
- **本地 Linux 预跑**:WSL/容器内 `dotnet test XUnitTest.Core -f net8.0/net10.0`ï¼ˆæ— éœ€ä»»ä½•å¹³å°å¼€å…³ï¼‰ã€‚
### 7.2 LA64(linux-loongarch64,社区支æŒå¹³å°ï¼‰
- **现状**:官方ä¸å‘ runtime packã€æ— NativeAOT 支æŒï¼ˆILCompiler æºç å« LoongArch64 åŽç«¯ä½†ä¸æž„æˆæ‰¿è¯ºï¼‰ã€‚龙芯 [loongson/dotnet](https://github.com/loongson/dotnet) æä¾› .NET 8/9/10 SDKï¼ˆå½“å‰ v10.0.112),pack èµ° `https://lnuget.loongnix.cn/v3/index.json`。
- **CI 方案(观察期,人工 `workflow_dispatch` 触å‘,失败ä¸é˜»å¡žï¼‰**:docker + QEMU 用户æ€ä»¿çœŸï¼ˆloong64 binfmt)+ 龙芯 SDK 在 loong64 容器内执行 —— 裸宿主缺 LA64 动æ€åŠ è½½å™¨ï¼ˆ`Could not open /lib64/ld-linux-loongarch-lp64d.so.1`),LA64 二进制必须在容器内è¿è¡Œï¼›åŸºç¡€é•œåƒ `lcr.loongnix.cn/debian:14-slim`(Debian unstable çš„ loong64 端å£ï¼Œè‡ªå¸¦ loader,apt æŒ‡å‘ deb.debian.org å¯ç”¨ï¼‰ï¼Œå®¹å™¨å†…补装 libicu/libssl,使全çƒåŒ–/åŠ å¯†ç”¨ä¾‹ä¸Žå…¶å®ƒ Linux job 行为一致。LA64 上 vstest ä¸å¯ç”¨ï¼ˆé¾™èН SDK 版ä¸è®¤è¯† LoongArch64 æž¶æž„ã€å®¿ä¸»ç‰ˆä¸º x64 R2R å¤åˆé•œåƒåŠ è½½å³ BadImageFormatExceptionï¼‰ï¼Œå•æµ‹æ”¹ä¸º `xunit.runner.utility` 构建的自宿主执行器:宿主管还原与构建(RID æ— å…³ IL),容器内以 LA64 è¿è¡Œæ—¶ç›´æŽ¥æ‰§è¡Œæµ‹è¯•程åºé›†ï¼›å¦è®¾ `DOTNET_EnableHWIntrinsic=0` è§„é¿ä»¿çœŸå±‚éžæ³•指令。QEMU ä¸‹æ•´å¥—å•æµ‹å®žæµ‹ ≥2 å°æ—¶ä»æœªè·‘完,故 2026-10-17 起转观察期:`test.yml` 与 `aot.yml` çš„ LA64 job 仅人工触å‘ã€push/PR ä¸å‚与ã€å¤±è´¥ä¸é˜»å¡žï¼ˆ`continue-on-error`)。
- **自托管接入(有真机åŽå‡çº§ä¸ºé˜»æ–级)**:
1. 龙芯 Linux 机器接入 GitHub Actions self-hosted runner(社区已有 runner å®¹å™¨é•œåƒ `kubernetes-loong64/actions-runner-loong64`);
2. 在 `aot.yml` / `test.yml` å¢žåŠ `runs-on: [self-hosted, loongarch64]` çš„ job,å¤ç”¨ QEMU job çš„æ¥éª¤ï¼ˆåŽ»æŽ‰ qemu 安装与仿真环境å˜é‡ï¼‰ï¼›
3. çœŸæœºè½¬ç»¿åŽæŠŠçŠ¶æ€åŒæ¥è¿›æœ¬èŠ‚è¡¨æ ¼å¹¶è€ƒè™‘è½¬é˜»æ–。
### 7.3 明确排除(é¿å…åå¤è®¨è®ºï¼‰
| ç›®æ ‡ | 排除ç†ç”± |
|---|---|
| Android / iOS | ä¸å¹¶å…¥ `dotnet test` çŸ©é˜µï¼ˆåº”ç”¨æ¨¡åž‹ç›®æ ‡ï¼Œæµ‹è¯•å®¿ä¸»ä¸åŒï¼‰ï¼›å·²ç”±ç‹¬ç«‹ `.github/workflows/mobile.yml` 覆盖:Android API 36 模拟器(`reactivecircus/android-emulator-runner`)+ iOS `macos-26` 模拟器,跑 `Samples/Mobile.Core` 共享冒烟(21 用例),路径触å‘å« `NewLife.Core/**`ã€`NewLife.Core.SourceGenerator/**` 与 `Directory.Build.props`ï¼›è¯¦è§ `Doc/移动端技术架构.md` §5.1 |
| tvOS / macCatalyst / WASM | åº”ç”¨æ¨¡åž‹ç±»ç›®æ ‡ï¼Œæœ¬ä»“æ— å¯¹åº”å†’çƒŸå®¿ä¸»ï¼Œä¸éªŒè¯ |
| FreeBSD / OpenBSD | æ— æ‰˜ç®¡ runnerï¼Œæ— å®˜æ–¹/社区 runtime pack æ¸ é“;纯托管库验è¯ä»·å€¼ä½Žï¼Œéœ€è¦æ—¶æŒ‰ LA64 çš„ QEMU é…æ–¹å¦ç«‹ä¸“项 |
| linux-ppc64le | QEMU 8.2 / 9.2 下 Ubuntu .NET 8/10 çš„ `(Int32)double` æ’为错值(`3.0→0`,`Int64` æ£å¸¸ï¼›native C æ£ç¡®ã€æ¢ `-cpu power8/9/10` 与è¿è¡Œå¼€å…³å‡æ— æ•ˆï¼‰ï¼Œæ— æ³•æ®ä»¿çœŸç»“果判定支æŒï¼›å®˜æ–¹æ— 托管 ppc64le runner,需真机 |
| MIPS64 | .NET(Core/5+)从未支æŒã€æ— SDK æ¸ é“;龙芯已从 MIPS64 è¿ç§»åˆ° LoongArchï¼ˆè§ Â§7.4),本仓历å²ä¹Ÿä»Žæœªæœ‰è¿‡ MIPS CI,ä¸å†çº³å…¥çŸ©é˜µ |
| Windows x64→Linux äº¤å‰ NativeAOT | å®˜æ–¹ä¸æ”¯æŒè·¨ OS 编译 |
### 7.4 指令集å–èˆï¼ˆä¸ºä»€ä¹ˆæ˜¯è¿™ä¸‰å®¶ï¼‰
| å¹³å° | è¿è¡Œæ—¶æ¸ é“ï¼ˆå·²æ ¸å®žï¼‰ | 独特价值 | 结论 |
|---|---|---|---|
| linux-riscv64 | 社区构建 [filipnavara/dotnet-riscv](https://github.com/filipnavara/dotnet-riscv) 跟踪 dotnet VMR 免釿ž„å»ºï¼Œå·²å‘ `10.0.113`(glibc / musl 两档);官方ä¸å‘ runtime pack | æ–° JIT åŽç«¯ + å¼±å†…å˜æ¨¡åž‹ï¼›å›½äº§ç¡¬ä»¶ä¸»çº¿ï¼›ç‰ˆæœ¬ä¸Žä»“库 net10 å¯¹é½ | 已接入(观察期) |
| linux-s390x | .NET 10 å®˜æ–¹æ”¯æŒæ¸…å•在 RHEL / CentOS Stream 明确列出 s390xï¼›Ubuntu 24.04 å®˜æ–¹æºæœ‰ `dotnet-runtime-10.0` | **大端**:仓库近百处å—节åºåˆ¤æ–(`SpanReader/Writer`ã€`BitConverter`ã€`BinaryPrimitives`,默认 `IsLittleEndian=true`ï¼‰åªæœ‰å¤§ç«¯èƒ½éªŒè¯ | 已接入(观察期),价值最高 |
| linux-ppc64le | åŒ s390xï¼ˆå®˜æ–¹æ¸…å• + Ubuntu 包) | 64 ä½å°ç«¯ + å¼±å†…å˜æ¨¡åž‹ï¼›æ— 大端差异 | ä¸åšï¼ˆQEMU 下è¿è¡Œæ—¶è½¬æ¢å¼‚常,需真机) |
| linux-armv6 | æ— å®˜æ–¹ runtime pack / ä¸»æµæ¸ é“ | arm32 已由 `linux-arm`(QEMU JIT 冒烟)覆盖 | ä¸åš |
| MIPS64 | æ— ï¼ˆMono 时代é—留,龙芯已转 LoongArch) | æ— æ–°å¢žè¦†ç›–é¢ | **ä¸åšï¼Œä¸å†è®¨è®º** |
| FreeBSD / OpenBSD | runtime 有 crossrootfsï¼Œä½†æ— æ‰˜ç®¡ runnerã€æ— runtime pack | 纯托管库价值低 | ä¸åš |
- **自宿主执行器**:`Tools/SelfHostRunner`(`--namespace A,B`(精确匹é…)/ `--class X` / `--root` / `--list`ï¼Œè¿‡æ»¤æ— åŒ¹é…返回 3)由宿主构建ã€å®¹å™¨å†…执行;LA64 ä»ç”¨ job 内è”版,åŽç»ç»Ÿä¸€ã€‚
- **ä¸ºä»€ä¹ˆè¦æµ‹æŒ‡ä»¤é›†**:本仓没有 `System.Runtime.Intrinsics` / `Vector128/256` 代ç ,也没有 Linux ä¾§ P/Invoke(仅 Windows/iOS/macOS)。矩阵验è¯çš„æ˜¯ JIT/AOT 在新åŽç«¯ä¸Šçš„æ£ç¡®æ€§ã€**å—节åºå‡è®¾**(s390x æ˜¯å”¯ä¸€ç¡¬è¯æ®ï¼‰ã€å¼±å†…å˜æ¨¡åž‹ä¸‹çš„å¹¶å‘原è¯ï¼ˆRISC-V / ppc64leï¼‰ä»¥åŠ BCL 行为差异(`MachineInfo`ã€OpenSSL åŠ å¯†ã€ç«¯åºç›¸å…³åºåˆ—化)。
- **è¿è¡Œæ—¶æ¥æºçº¦æŸ**:NuGet 上没有 `Microsoft.NETCore.App.Runtime.linux-{riscv64,s390x,ppc64le,loongarch64}` åŒ…ï¼Œå› æ¤åªèƒ½æ¡†æž¶ä¾èµ–è¿è¡Œï¼ˆå®¿ä¸»æž„建 RID æ— å…³ IL + ç›®æ ‡æž¶æž„è¿è¡Œæ—¶æ‰§è¡Œï¼‰ï¼Œä¸èƒ½ self-contained / 交å‰å‘布。
- **版本é”定与替æ¢é¢„案**:riscv64 固定 `dotnet-sdk-10.0.113-linux-riscv64.tar.gz`;上游æ–供时改用 [riscv-forks/dotnet-riscv](https://github.com/riscv-forks/dotnet-riscv);若 Ubuntu åŽç»åœ¨ riscv64 ç«¯å£æä¾› `dotnet-*` 包,则改走 apt,与 s390x/ppc64le åŒé…方。
- **s390x 首轮失败分æµ**ï¼šå¤§ç«¯ä¼šåŒæ—¶æš´éœ²"用例å‡è®¾å°ç«¯"与真实å—节åºç¼ºé™·â€”—å‰è€…按《测试稳定性规约》§1 规则 7/8 显å¼è·³è¿‡å¹¶ç•™ç—•,åŽè€…记入《功能清å•》待修å¤é¡¹åŽä¿®äº§å“ï¼›ä¸å¾—为转绿而放宽æ–言。
- **本地 WSL å¤çŽ°ï¼ˆ2026-10-18 实测)**:WSL2 已注册 `binfmt_misc`(`qemu-riscv64/s390x`);下载 `ubuntu-base-24.04.3-base-<arch>.tar.gz` 解出 rootfs,`chroot` å†…è£…ç›®æ ‡è¿è¡Œæ—¶ï¼ˆs390x 用 `dotnet-runtime-10.0`,riscv64 用社区 SDK),宿主构建的 IL 挂载到 `/src` 直接执行。chroot å‰å¿…é¡» `mount --bind /dev` 与 `mount -t proc proc`,å¦åˆ™ .NET 报 `Mono requires /proc to be mounted`。
- **s390x 实测结论**:WSL + Ubuntu 24.04 rootfs + QEMU(å•çº¿ç¨‹ï¼‰ä¸‹å…¨é‡ **3573 通过 / 5 跳过 / 0 失败**。修å¤çš„产å“缺陷:`BinaryGeneral` å–åã€`IOHelper` 主机åºã€`Utility`/`DSAHelper` 主机åºã€`TcpConnectionInformation2` IPv4/IPv6 è§£æžã€`DbTable` 行数;用例侧消除 `BitConverter` 主机åºå‡è®¾ä¸Ž CSV 文件å åŠ ã€‚QEMU å¶å‘ `SIGSEGV` ç”±å•线程 + "æ— TOTAL 自动é‡è¯•" 兜底。
- **riscv64 实测结论**:社区 SDK `10.0.113` + QEMU(å•çº¿ç¨‹ï¼‰ä¸‹å…¨é‡ **3573 通过 / 5 跳过 / 0 失败**,与 x64 结果一致。
- **ppc64le 排除结论**:Ubuntu 24.04 çš„ .NET 8/10 在 QEMU 8.2/9.2 下 `(Int32)double` æ’为错值(`3.0→0`,`Int64` æ£å¸¸ï¼‰ï¼Œ`SamplingTests` 必然失败;native C åŒæ ·è½¬æ¢æ£ç¡®ã€åˆ‡æ¢ `-cpu power8/9/10` 与 `DOTNET_JitMinOpts/ReadyToRun/TieredCompilation` 凿— 效 → 属仿真层与è¿è¡Œæ—¶ç»„åˆé™åˆ¶ã€‚`test.yml` çš„ ppc64le job 已移除,改由真机或 Red Hat/IBM 构建验è¯åŽå†è®®ã€‚
- **README å¾½ç« **:`arch` å¾½ç« å·²åŠ å…¥ `riscv64 / s390x`(11 份 README åŒæ¥ï¼‰ã€‚
> äº‹å®žä¾æ®ï¼ˆ2026-10 è”ç½‘æ ¸å®žï¼‰ï¼šGitHub 托管 runner æ ‡å‡†è¡¨ï¼ˆå…¬å¼€ä»“åº“æ ‡å‡† runner å…费且ä¸é™é‡ï¼‰ï¼›NativeAOT 交å‰ç¼–译文档(learn.microsoft.com/dotnet/core/deploying/native-aot/cross-compileï¼‰ï¼›ç¤¾åŒºå¹³å°æ¸…å•(dotnet/runtime `docs/workflow/building/coreclr/cross-building.md`);龙芯 SDK å‘布页与 lnuget æºã€‚
|