mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-29 08:29:10 +01:00
Compare commits
3 Commits
cinnamon-m
...
yuleng/aot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a2d8d7851 | ||
|
|
f882bc3370 | ||
|
|
d872e844e7 |
1
deps/cxxopts
vendored
Submodule
1
deps/cxxopts
vendored
Submodule
Submodule deps/cxxopts added at 12e496da3d
51
tools/README-CmdPal-AOT-Analysis.md
Normal file
51
tools/README-CmdPal-AOT-Analysis.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# PowerToys CmdPal AOT 分析工具
|
||||
|
||||
这个工具包用于分析 PowerToys CmdPal 在启用 AOT (Ahead-of-Time) 编译时被移除的类型。
|
||||
|
||||
## 核心文件
|
||||
|
||||
### 分析工具 (`tools/TrimmingAnalyzer/`)
|
||||
- `TrimmingAnalyzer.csproj` - 项目文件
|
||||
- `Program.cs` - 主程序入口
|
||||
- `TypeAnalyzer.cs` - 程序集类型分析引擎
|
||||
- `ReportGenerator.cs` - 报告生成器 (Markdown/XML/JSON)
|
||||
|
||||
### 脚本文件 (`tools/build/`)
|
||||
- `Generate-CmdPalTrimmingReport.ps1` - 主要分析脚本(包含完整说明和自动化流程)
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 前提条件
|
||||
- Visual Studio 2022 with C++ workload
|
||||
- Windows SDK
|
||||
- 使用 Developer Command Prompt for VS 2022
|
||||
|
||||
### 运行分析
|
||||
```powershell
|
||||
cd C:\Users\yuleng\PowerToys
|
||||
.\tools\build\Generate-CmdPalTrimmingReport.ps1
|
||||
```
|
||||
|
||||
### 输出报告
|
||||
- `TrimmedTypes.md` - 人类可读的 Markdown 报告
|
||||
- `TrimmedTypes.rd.xml` - 运行时指令以保留类型
|
||||
- JSON 格式的分析数据
|
||||
|
||||
## 分析原理
|
||||
|
||||
1. **Debug 构建** - 不启用 AOT,保留所有类型
|
||||
2. **Release 构建** - 启用 AOT,移除未使用的类型
|
||||
3. **程序集比较** - 识别被 AOT 优化移除的类型
|
||||
4. **报告生成** - 生成详细的优化效果报告
|
||||
|
||||
## 价值
|
||||
|
||||
- 显示 AOT 优化的有效性
|
||||
- 识别被消除的未使用代码
|
||||
- 帮助理解二进制大小减少
|
||||
- 协助排查运行时反射问题
|
||||
- 为性能优化决策提供数据
|
||||
|
||||
---
|
||||
|
||||
*工具状态: 已完成,等待 Visual Studio C++ 构建环境配置后即可使用*
|
||||
20
tools/TrimmingAnalyzer/Models/TypeInfo.cs
Normal file
20
tools/TrimmingAnalyzer/Models/TypeInfo.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TrimmingAnalyzer.Models
|
||||
{
|
||||
public class TypeInfo
|
||||
{
|
||||
public string FullName { get; set; } = string.Empty;
|
||||
public string Namespace { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsPublic { get; set; }
|
||||
public bool IsSealed { get; set; }
|
||||
public bool IsAbstract { get; set; }
|
||||
public bool IsInterface { get; set; }
|
||||
public bool IsEnum { get; set; }
|
||||
public bool IsDelegate { get; set; }
|
||||
public string? BaseType { get; set; }
|
||||
public List<string> Interfaces { get; set; } = new();
|
||||
public int MemberCount { get; set; }
|
||||
}
|
||||
}
|
||||
59
tools/TrimmingAnalyzer/Program.cs
Normal file
59
tools/TrimmingAnalyzer/Program.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TrimmingAnalyzer
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 3)
|
||||
{
|
||||
Console.WriteLine("Usage: TrimmingAnalyzer <untrimmed.dll> <trimmed.dll> <output-dir> [formats]");
|
||||
Console.WriteLine("Formats: rdxml,markdown (default: rdxml,markdown)");
|
||||
return;
|
||||
}
|
||||
|
||||
var untrimmedPath = Path.GetFullPath(args[0]);
|
||||
var trimmedPath = Path.GetFullPath(args[1]);
|
||||
var outputDir = Path.GetFullPath(args[2]);
|
||||
var formats = args.Length > 3 ? args[3].Split(',') : new[] { "rdxml", "markdown" };
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Analyzing assemblies...");
|
||||
var analyzer = new TypeAnalyzer();
|
||||
var removedTypes = analyzer.GetRemovedTypes(untrimmedPath, trimmedPath);
|
||||
|
||||
Console.WriteLine($"Found {removedTypes.Count} trimmed types");
|
||||
|
||||
var generator = new ReportGenerator();
|
||||
|
||||
foreach (var format in formats)
|
||||
{
|
||||
switch (format.Trim().ToLower())
|
||||
{
|
||||
case "rdxml":
|
||||
var rdxmlPath = Path.Combine(outputDir, "TrimmedTypes.rd.xml");
|
||||
generator.GenerateRdXml(removedTypes, rdxmlPath);
|
||||
Console.WriteLine($"Generated: {rdxmlPath}");
|
||||
break;
|
||||
case "markdown":
|
||||
var markdownPath = Path.Combine(outputDir, "TrimmedTypes.md");
|
||||
generator.GenerateMarkdown(removedTypes, markdownPath);
|
||||
Console.WriteLine($"Generated: {markdownPath}");
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"Unknown format: {format}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
tools/TrimmingAnalyzer/ReportGenerator.cs
Normal file
167
tools/TrimmingAnalyzer/ReportGenerator.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Xml.Linq;
|
||||
using TrimmingAnalyzer.Models;
|
||||
|
||||
namespace TrimmingAnalyzer
|
||||
{
|
||||
public class ReportGenerator
|
||||
{
|
||||
public void GenerateRdXml(List<TypeInfo> removedTypes, string outputPath)
|
||||
{
|
||||
var typesByNamespace = removedTypes.GroupBy(t => t.Namespace);
|
||||
|
||||
// Define the namespace
|
||||
XNamespace ns = "http://schemas.microsoft.com/netfx/2013/01/metadata";
|
||||
|
||||
var doc = new XDocument(
|
||||
new XElement(ns + "Directives",
|
||||
new XElement(ns + "Application",
|
||||
new XComment($"CmdPal Trimming Report - Generated on {DateTime.Now:yyyy-MM-dd HH:mm:ss}"),
|
||||
new XComment($"Total types trimmed: {removedTypes.Count}"),
|
||||
new XComment("TrimMode: partial (as configured in Microsoft.CmdPal.UI.csproj)"),
|
||||
new XElement(ns + "Assembly",
|
||||
new XAttribute("Name", "Microsoft.CmdPal.UI"),
|
||||
new XAttribute("Dynamic", "Required All"),
|
||||
typesByNamespace.Select(g =>
|
||||
new XElement(ns + "Namespace",
|
||||
new XAttribute("Name", g.Key),
|
||||
new XAttribute("Preserve", "All"),
|
||||
new XAttribute("Dynamic", "Required All"),
|
||||
g.Select(type =>
|
||||
new XElement(ns + "Type",
|
||||
new XAttribute("Name", type.Name),
|
||||
new XAttribute("Dynamic", "Required All"),
|
||||
new XAttribute("Serialize", "All"),
|
||||
new XAttribute("DataContractSerializer", "All"),
|
||||
new XAttribute("DataContractJsonSerializer", "All"),
|
||||
new XAttribute("XmlSerializer", "All"),
|
||||
new XAttribute("MarshalObject", "All"),
|
||||
new XAttribute("MarshalDelegate", "All")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? ".");
|
||||
doc.Save(outputPath);
|
||||
}
|
||||
|
||||
public void GenerateMarkdown(List<TypeInfo> removedTypes, string outputPath)
|
||||
{
|
||||
GenerateMarkdown(removedTypes, outputPath, null);
|
||||
}
|
||||
|
||||
public void GenerateMarkdown(List<TypeInfo> removedTypes, string outputPath, List<string>? assemblyNames)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("# CmdPal Debug vs AOT Release Comparison Report");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"**Generated:** {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"**Comparison:** Debug Build (no AOT) vs Release Build (with AOT)");
|
||||
sb.AppendLine($"**Purpose:** Show types removed when enabling AOT compilation in Release mode");
|
||||
sb.AppendLine();
|
||||
|
||||
if (assemblyNames != null && assemblyNames.Count > 0)
|
||||
{
|
||||
sb.AppendLine($"**Analyzed assemblies:** {string.Join(", ", assemblyNames.Distinct().OrderBy(x => x))}");
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
sb.AppendLine($"**Total types removed by AOT:** {removedTypes.Count}");
|
||||
sb.AppendLine();
|
||||
|
||||
// Summary by namespace
|
||||
sb.AppendLine("## Summary by Namespace");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("| Namespace | Types Trimmed |");
|
||||
sb.AppendLine("|-----------|---------------|");
|
||||
|
||||
foreach (var group in removedTypes.GroupBy(t => t.Namespace).OrderBy(g => g.Key))
|
||||
{
|
||||
sb.AppendLine($"| `{group.Key}` | {group.Count()} |");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("## Detailed Type List");
|
||||
sb.AppendLine();
|
||||
|
||||
foreach (var group in removedTypes.GroupBy(t => t.Namespace).OrderBy(g => g.Key))
|
||||
{
|
||||
sb.AppendLine($"### {group.Key}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("| Type | Kind | Visibility | Base Type | Interfaces | Members |");
|
||||
sb.AppendLine("|------|------|------------|-----------|------------|---------|");
|
||||
|
||||
foreach (var type in group.OrderBy(t => t.Name))
|
||||
{
|
||||
var kind = GetTypeKind(type);
|
||||
var visibility = type.IsPublic ? "Public" : "Internal";
|
||||
var baseType = string.IsNullOrEmpty(type.BaseType) ? "-" : $"`{type.BaseType.Split('.').Last()}`";
|
||||
var interfaces = type.Interfaces.Any()
|
||||
? string.Join(", ", type.Interfaces.Take(3).Select(i => $"`{i.Split('.').Last()}`")) +
|
||||
(type.Interfaces.Count > 3 ? "..." : "")
|
||||
: "-";
|
||||
|
||||
sb.AppendLine($"| `{type.Name}` | {kind} | {visibility} | {baseType} | {interfaces} | {type.MemberCount} |");
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
// Add usage instructions
|
||||
sb.AppendLine("## How to Use This Report");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("If you need to preserve any of these types from trimming:");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("1. Copy the relevant entries from `TrimmedTypes.rd.xml` to your project's `rd.xml` file");
|
||||
sb.AppendLine("2. Or use `[DynamicallyAccessedMembers]` attributes in your code");
|
||||
sb.AppendLine("3. Or use `[DynamicDependency]` attributes to preserve specific members");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("Note: This report shows types that are present in Debug builds but removed in AOT Release builds.");
|
||||
sb.AppendLine("AOT compilation removes unused types and members to reduce binary size and improve startup performance.");
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? ".");
|
||||
File.WriteAllText(outputPath, sb.ToString());
|
||||
}
|
||||
|
||||
public void GenerateJson(List<TypeInfo> removedTypes, string outputPath, string assemblyName)
|
||||
{
|
||||
var analysisResult = new
|
||||
{
|
||||
AssemblyName = assemblyName,
|
||||
GeneratedAt = DateTime.Now,
|
||||
TotalTypes = removedTypes.Count,
|
||||
RemovedTypes = removedTypes.OrderBy(t => t.FullName).ToList()
|
||||
};
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(analysisResult, options);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? ".");
|
||||
File.WriteAllText(outputPath, json);
|
||||
}
|
||||
|
||||
private string GetTypeKind(TypeInfo type)
|
||||
{
|
||||
if (type.IsInterface) return "Interface";
|
||||
if (type.IsEnum) return "Enum";
|
||||
if (type.IsDelegate) return "Delegate";
|
||||
if (type.IsAbstract) return "Abstract Class";
|
||||
if (type.IsSealed) return "Sealed Class";
|
||||
return "Class";
|
||||
}
|
||||
}
|
||||
}
|
||||
26
tools/TrimmingAnalyzer/TrimmingAnalyzer.csproj
Normal file
26
tools/TrimmingAnalyzer/TrimmingAnalyzer.csproj
Normal file
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<WarningsNotAsErrors />
|
||||
<NoWarn>SA1633;SA1400;SA1518;SA1516;SA1503;SA1111;SA1116;SA1122;SA1028;SA1413;SA1513;CA1311;CA1304;CA1305;CA1860;CA1852</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="TypeAnalyzer.cs" />
|
||||
<Compile Include="ReportGenerator.cs" />
|
||||
<Compile Include="Models\TypeInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
79
tools/TrimmingAnalyzer/TypeAnalyzer.cs
Normal file
79
tools/TrimmingAnalyzer/TypeAnalyzer.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using TrimmingAnalyzer.Models;
|
||||
|
||||
namespace TrimmingAnalyzer
|
||||
{
|
||||
public class TypeAnalyzer
|
||||
{
|
||||
public List<Models.TypeInfo> GetRemovedTypes(string untrimmedPath, string trimmedPath)
|
||||
{
|
||||
if (!File.Exists(untrimmedPath))
|
||||
{
|
||||
throw new FileNotFoundException($"Untrimmed assembly not found: {untrimmedPath}");
|
||||
}
|
||||
|
||||
if (!File.Exists(trimmedPath))
|
||||
{
|
||||
throw new FileNotFoundException($"Trimmed assembly not found: {trimmedPath}");
|
||||
}
|
||||
|
||||
var removedTypes = new List<Models.TypeInfo>();
|
||||
|
||||
var untrimmedContext = new AssemblyLoadContext("Untrimmed", true);
|
||||
var trimmedContext = new AssemblyLoadContext("Trimmed", true);
|
||||
|
||||
try
|
||||
{
|
||||
var untrimmedAssembly = untrimmedContext.LoadFromAssemblyPath(untrimmedPath);
|
||||
var trimmedAssembly = trimmedContext.LoadFromAssemblyPath(trimmedPath);
|
||||
|
||||
var untrimmedTypes = untrimmedAssembly.GetTypes().Where(t => t.FullName != null).ToDictionary(t => t.FullName!);
|
||||
var trimmedTypeNames = trimmedAssembly.GetTypes().Where(t => t.FullName != null).Select(t => t.FullName!).ToHashSet();
|
||||
|
||||
foreach (var kvp in untrimmedTypes)
|
||||
{
|
||||
if (!trimmedTypeNames.Contains(kvp.Key))
|
||||
{
|
||||
var type = kvp.Value;
|
||||
var typeInfo = new Models.TypeInfo
|
||||
{
|
||||
FullName = type.FullName ?? string.Empty,
|
||||
Namespace = type.Namespace ?? "Global",
|
||||
Name = type.Name,
|
||||
IsPublic = type.IsPublic,
|
||||
IsSealed = type.IsSealed,
|
||||
IsAbstract = type.IsAbstract,
|
||||
IsInterface = type.IsInterface,
|
||||
IsEnum = type.IsEnum,
|
||||
IsDelegate = type.IsSubclassOf(typeof(Delegate)),
|
||||
BaseType = type.BaseType?.FullName,
|
||||
Interfaces = type.GetInterfaces().Select(i => i.FullName ?? string.Empty).ToList(),
|
||||
MemberCount = type.GetMembers(
|
||||
BindingFlags.Public | BindingFlags.NonPublic |
|
||||
BindingFlags.Instance | BindingFlags.Static |
|
||||
BindingFlags.DeclaredOnly).Length,
|
||||
};
|
||||
|
||||
removedTypes.Add(typeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Error analyzing assemblies: {ex.Message}", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
untrimmedContext.Unload();
|
||||
trimmedContext.Unload();
|
||||
}
|
||||
|
||||
return removedTypes.OrderBy(t => t.Namespace).ThenBy(t => t.Name).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
168
tools/build/Generate-CmdPalTrimmingReport.ps1
Normal file
168
tools/build/Generate-CmdPalTrimmingReport.ps1
Normal file
@@ -0,0 +1,168 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
PowerToys CmdPal AOT Trimming Analysis - Generates assembly comparison reports
|
||||
|
||||
.DESCRIPTION
|
||||
This script builds CmdPal UI with and without AOT optimization, then uses TrimmingAnalyzer
|
||||
to analyze the differences and generate reports showing which types are removed by AOT.
|
||||
|
||||
ANALYSIS PROCESS:
|
||||
1. Build Debug version (no AOT optimization)
|
||||
2. Build Release version (with AOT optimization)
|
||||
3. Compare assemblies to identify removed types
|
||||
4. Generate reports: TrimmedTypes.md, TrimmedTypes.rd.xml
|
||||
|
||||
REQUIREMENTS:
|
||||
• Visual Studio 2022 with C++ workload
|
||||
• Windows SDK
|
||||
• Use Developer Command Prompt for VS 2022
|
||||
|
||||
OUTPUT REPORTS:
|
||||
• TrimmedTypes.md - Human-readable Markdown report
|
||||
• TrimmedTypes.rd.xml - Runtime directives to preserve types
|
||||
• Analysis JSON data for further processing
|
||||
|
||||
.PARAMETER Configuration
|
||||
Build configuration (Debug/Release). Defaults to Release
|
||||
|
||||
.PARAMETER EnableAOT
|
||||
Whether to enable AOT compilation. Defaults to true
|
||||
|
||||
.EXAMPLE
|
||||
.\Generate-CmdPalTrimmingReport.ps1
|
||||
|
||||
Runs the complete AOT trimming analysis with default settings
|
||||
|
||||
.NOTES
|
||||
Author: PowerToys CmdPal AOT Analysis Tool
|
||||
Purpose: Show types removed when enabling AOT compilation
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$Configuration = "Release",
|
||||
[bool]$EnableAOT = $true
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "======================================" -ForegroundColor Cyan
|
||||
Write-Host "PowerToys CmdPal AOT Trimming Analysis" -ForegroundColor Cyan
|
||||
Write-Host "======================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "PURPOSE: Generate reports showing types removed by AOT optimization" -ForegroundColor Yellow
|
||||
Write-Host "OUTPUT: TrimmedTypes.md, TrimmedTypes.rd.xml, analysis data" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
# Get paths
|
||||
$rootDir = Resolve-Path (Join-Path $PSScriptRoot "..\..")
|
||||
$cmdPalProject = Join-Path $rootDir "src\modules\cmdpal\Microsoft.CmdPal.UI\Microsoft.CmdPal.UI.csproj"
|
||||
$cmdPalDir = Split-Path -Parent $cmdPalProject
|
||||
$analyzerProject = Join-Path $rootDir "tools\TrimmingAnalyzer\TrimmingAnalyzer.csproj"
|
||||
|
||||
# Build paths
|
||||
$tempDir = Join-Path $env:TEMP "CmdPalTrimAnalysis_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||
$untrimmedDir = Join-Path $tempDir "untrimmed"
|
||||
$trimmedDir = Join-Path $tempDir "trimmed"
|
||||
|
||||
# Ensure all NuGet packages are restored
|
||||
Write-Host "Restoring NuGet packages..." -ForegroundColor Yellow
|
||||
& dotnet restore $cmdPalProject
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "Package restore had some issues, but continuing..."
|
||||
}
|
||||
|
||||
try {
|
||||
# Create directories
|
||||
New-Item -ItemType Directory -Path $untrimmedDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $trimmedDir -Force | Out-Null
|
||||
|
||||
# Build TrimmingAnalyzer
|
||||
Write-Host "Building TrimmingAnalyzer tool..." -ForegroundColor Yellow
|
||||
& dotnet build $analyzerProject -c Release
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to build TrimmingAnalyzer"
|
||||
}
|
||||
|
||||
# Build Debug mode without AOT (baseline for comparison)
|
||||
Write-Host "Building CmdPal in Debug mode without AOT (baseline)..." -ForegroundColor Yellow
|
||||
& dotnet publish $cmdPalProject `
|
||||
--configuration Debug `
|
||||
--runtime win-x64 `
|
||||
--self-contained true `
|
||||
--property:PublishTrimmed=false `
|
||||
--property:EnableCmdPalAOT=false `
|
||||
--property:PublishAot=false `
|
||||
--verbosity minimal
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to build Debug baseline version"
|
||||
}
|
||||
|
||||
# Copy baseline (Debug without AOT) output to analysis directory
|
||||
$baselineOutput = Join-Path $cmdPalDir "bin\Debug\net9.0-windows10.0.26100.0\win-x64\publish"
|
||||
Copy-Item "$baselineOutput\Microsoft.CmdPal.UI.dll" $untrimmedDir -Force
|
||||
# Copy all dependencies to help with assembly resolution
|
||||
Get-ChildItem "$baselineOutput\*.dll" | ForEach-Object {
|
||||
if ($_.Name -ne "Microsoft.CmdPal.UI.dll") {
|
||||
Copy-Item $_.FullName $untrimmedDir -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Write-Host "Copied Debug baseline DLLs from: $baselineOutput"
|
||||
|
||||
# Build Release mode with AOT enabled
|
||||
Write-Host "Building CmdPal in Release mode with AOT enabled..." -ForegroundColor Yellow
|
||||
& dotnet publish $cmdPalProject `
|
||||
--configuration Release `
|
||||
--runtime win-x64 `
|
||||
--self-contained true `
|
||||
--property:PublishTrimmed=false `
|
||||
--property:EnableCmdPalAOT=true `
|
||||
--property:PublishAot=true `
|
||||
--verbosity minimal
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to build AOT+trimmed version"
|
||||
}
|
||||
|
||||
# Copy AOT+trimmed output to analysis directory
|
||||
$trimmedOutput = Join-Path $cmdPalDir "bin\$Configuration\net9.0-windows10.0.26100.0\win-x64\publish"
|
||||
Copy-Item "$trimmedOutput\Microsoft.CmdPal.UI.dll" $trimmedDir -Force
|
||||
# Copy all dependencies to help with assembly resolution
|
||||
Get-ChildItem "$trimmedOutput\*.dll" | ForEach-Object {
|
||||
if ($_.Name -ne "Microsoft.CmdPal.UI.dll") {
|
||||
Copy-Item $_.FullName $trimmedDir -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Write-Host "Copied Release AOT DLLs from: $trimmedOutput"
|
||||
|
||||
# Use new directory comparison method to compare all types
|
||||
Write-Host "Analyzing differences (Debug baseline vs Release AOT)..." -ForegroundColor Yellow
|
||||
Write-Host "Using advanced directory comparison to detect AOT-optimized types..." -ForegroundColor Cyan
|
||||
|
||||
# Use the new directory comparison feature
|
||||
& $analyzerPath --compare-directories "$untrimmedDir" "$trimmedDir" "$cmdPalDir" "rdxml,markdown,json" "TrimmedTypes"
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "Analysis completed successfully!" -ForegroundColor Green
|
||||
} else {
|
||||
throw "Analysis failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Write-Host "`n===== Analysis Complete =====" -ForegroundColor Cyan
|
||||
Write-Host "Reports generated in: $cmdPalDir" -ForegroundColor Green
|
||||
|
||||
# List the main combined reports
|
||||
$mainReports = @("TrimmedTypes.md", "TrimmedTypes.rd.xml")
|
||||
foreach ($report in $mainReports) {
|
||||
$reportPath = Join-Path $cmdPalDir $report
|
||||
if (Test-Path $reportPath) {
|
||||
Write-Host " - $report" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
# Cleanup
|
||||
if (Test-Path $tempDir) {
|
||||
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user