Update .NET Framework packaging

pull/635/head
NextTurn 2020-08-06 00:00:00 +08:00 committed by Next Turn
parent a16c93e558
commit 5546e655cc
6 changed files with 193 additions and 1 deletions

126
src/WinSW.Tasks/Trim.cs Normal file
View File

@ -0,0 +1,126 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Mono.Cecil;
namespace WinSW.Tasks
{
public sealed class Trim : Task
{
private readonly HashSet<TypeDefinition> usedTypes = new HashSet<TypeDefinition>();
[Required]
public string Path { get; set; }
public override bool Execute()
{
using var module = ModuleDefinition.ReadModule(this.Path, new ReaderParameters { ReadWrite = true });
this.WalkType(module.EntryPoint.DeclaringType);
var types = module.Types;
for (int i = types.Count - 1; i >= 0; i--)
{
var type = types[i];
if (type.FullName.Contains("WinSW.Plugins"))
{
this.WalkType(type);
}
}
for (int i = types.Count - 1; i >= 0; i--)
{
var type = types[i];
if (type.FullName == "<Module>")
{
continue;
}
if (this.usedTypes.Contains(type))
{
continue;
}
this.Log.LogMessage(MessageImportance.High, type.FullName);
types.RemoveAt(i);
}
module.Write();
return true;
}
private void WalkType(TypeReference typeRef)
{
if (typeRef is TypeSpecification typeSpec)
{
this.WalkType(typeSpec.ElementType);
if (typeRef is GenericInstanceType genericType)
{
foreach (var genericArg in genericType.GenericArguments)
{
this.WalkType(genericArg);
}
}
return;
}
if (typeRef is TypeDefinition typeDef)
{
if (!this.usedTypes.Add(typeDef))
{
return;
}
if (typeDef.DeclaringType != null)
{
this.WalkType(typeDef.DeclaringType);
}
if (typeDef.BaseType != null)
{
this.WalkType(typeDef.BaseType);
}
var methods = typeDef.Methods.ToList();
var bodies = methods.Where(m => m.HasBody).Select(m => m.Body);
var operands = bodies.SelectMany(b => b.Instructions).Select(i => i.Operand);
var types = typeDef.CustomAttributeTypes()
.Union(typeDef.GenericParameters.SelectMany(p => p.CustomAttributeTypes()))
.Union(typeDef.Interfaces.Select(i => i.InterfaceType))
.Union(typeDef.Fields.SelectMany(f => f.CustomAttributeTypes()))
.Union(typeDef.Fields.Select(f => f.FieldType))
.Union(typeDef.Properties.SelectMany(p => p.CustomAttributeTypes()))
.Union(typeDef.Events.SelectMany(e => e.CustomAttributeTypes()))
.Union(typeDef.Events.Select(e => e.EventType))
.Union(methods.SelectMany(m => m.CustomAttributeTypes()))
.Union(methods.SelectMany(m => m.GenericParameters).SelectMany(p => p.CustomAttributeTypes()))
.Union(methods.SelectMany(m => m.MethodReturnType.CustomAttributeTypes()))
.Union(methods.Select(m => m.ReturnType))
.Union(methods.SelectMany(m => m.Parameters).SelectMany(p => p.CustomAttributeTypes()))
.Union(methods.SelectMany(m => m.Parameters).Select(p => p.ParameterType))
.Union(bodies.SelectMany(b => b.Variables).Select(v => v.VariableType))
.Union(operands.OfType<TypeReference>())
.Union(operands.OfType<MemberReference>().Select(m => m.DeclaringType))
.Union(operands.OfType<GenericInstanceMethod>().SelectMany(m => m.GenericArguments));
foreach (var t in types)
{
this.WalkType(t);
}
}
}
}
internal static class Extensions
{
internal static IEnumerable<TypeReference> CustomAttributeTypes(this ICustomAttributeProvider provider)
{
return provider.HasCustomAttributes ? provider.CustomAttributes.Select(a => a.AttributeType) : Enumerable.Empty<TypeReference>();
}
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<LangVersion>latest</LangVersion>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.6.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,32 @@
#if NET461
using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using WinSW.Tests.Util;
using Xunit;
namespace WinSW.Tests
{
public sealed class MetadataTests
{
[Fact]
public void Extern()
{
var version = new Version(4, 0, 0, 0);
using var file = File.OpenRead(Path.Combine(Layout.ArtifactsDirectory, "WinSW.NET461.exe"));
using var peReader = new PEReader(file);
var metadataReader = peReader.GetMetadataReader();
foreach (var handle in metadataReader.AssemblyReferences)
{
var assembly = metadataReader.GetAssemblyReference(handle);
if (metadataReader.GetString(assembly.Name) != "System.IO.Compression")
{
Assert.Equal(version, assembly.Version);
}
}
}
}
}
#endif

View File

@ -19,6 +19,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp5.0'">
<PackageReference Include="System.Reflection.Metadata" Version="1.8.1" />
<Reference Include="System.ServiceProcess" />
</ItemGroup>

View File

@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinSW.Plugins", "WinSW.Plug
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinSW.Tests", "WinSW.Tests\WinSW.Tests.csproj", "{691DE22D-4565-4E3C-9CC7-918A0098219E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinSW.Tasks", "WinSW.Tasks\WinSW.Tasks.csproj", "{EFDE140A-BB31-4509-A835-766520FEAEB9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4975DCF4-C32C-43ED-A731-8FCC1F7E6746}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
@ -38,6 +40,10 @@ Global
{691DE22D-4565-4E3C-9CC7-918A0098219E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{691DE22D-4565-4E3C-9CC7-918A0098219E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{691DE22D-4565-4E3C-9CC7-918A0098219E}.Release|Any CPU.Build.0 = Release|Any CPU
{EFDE140A-BB31-4509-A835-766520FEAEB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EFDE140A-BB31-4509-A835-766520FEAEB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFDE140A-BB31-4509-A835-766520FEAEB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFDE140A-BB31-4509-A835-766520FEAEB9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -37,6 +37,10 @@
<ProjectReference Include="..\WinSW.Plugins\WinSW.Plugins.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<ProjectReference Include="..\WinSW.Tasks\WinSW.Tasks.csproj" />
</ItemGroup>
<Target Name="PublishCoreZip" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'netcoreapp3.1' and '$(PublishSingleFile)' != 'true'">
<MakeDir Directories="$(ArtifactsDir)" />
@ -64,6 +68,11 @@
<InputAssemblies>$(InputAssemblies) "$(OutDir)WinSW.Plugins.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)log4net.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.CommandLine.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.Buffers.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.Memory.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.Numerics.Vectors.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.Runtime.CompilerServices.Unsafe.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.ValueTuple.dll"</InputAssemblies>
<OutputAssembly>"$(ArtifactsDir)WinSW.$(TargetFrameworkSuffix).exe"</OutputAssembly>
</PropertyGroup>
@ -74,9 +83,13 @@
</PropertyGroup>
<MakeDir Directories="$(ArtifactsDir)" />
<Message Text="$(ILMergeCommand)" Importance="high" />
<Exec Command="$(ILMergeCommand)" />
</Target>
<UsingTask TaskName="WinSW.Tasks.Trim" AssemblyFile="..\WinSW.Tasks\bin\$(Configuration)\net461\WinSW.Tasks.dll" />
<Target Name="Trim" AfterTargets="Merge" Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<Trim Path="$(ArtifactsDir)WinSW.$(TargetFrameworkSuffix).exe" />
</Target>
</Project>