From 5546e655cc74be2c69bdca62f9c55ceaf20b939e Mon Sep 17 00:00:00 2001 From: NextTurn <45985406+NextTurn@users.noreply.github.com> Date: Thu, 6 Aug 2020 00:00:00 +0800 Subject: [PATCH] Update .NET Framework packaging --- src/WinSW.Tasks/Trim.cs | 126 +++++++++++++++++++++++++++++ src/WinSW.Tasks/WinSW.Tasks.csproj | 14 ++++ src/WinSW.Tests/MetadataTests.cs | 32 ++++++++ src/WinSW.Tests/WinSW.Tests.csproj | 1 + src/WinSW.sln | 6 ++ src/WinSW/WinSW.csproj | 15 +++- 6 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/WinSW.Tasks/Trim.cs create mode 100644 src/WinSW.Tasks/WinSW.Tasks.csproj create mode 100644 src/WinSW.Tests/MetadataTests.cs diff --git a/src/WinSW.Tasks/Trim.cs b/src/WinSW.Tasks/Trim.cs new file mode 100644 index 0000000..b8a1b90 --- /dev/null +++ b/src/WinSW.Tasks/Trim.cs @@ -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 usedTypes = new HashSet(); + + [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 == "") + { + 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()) + .Union(operands.OfType().Select(m => m.DeclaringType)) + .Union(operands.OfType().SelectMany(m => m.GenericArguments)); + + foreach (var t in types) + { + this.WalkType(t); + } + } + } + } + + internal static class Extensions + { + internal static IEnumerable CustomAttributeTypes(this ICustomAttributeProvider provider) + { + return provider.HasCustomAttributes ? provider.CustomAttributes.Select(a => a.AttributeType) : Enumerable.Empty(); + } + } +} diff --git a/src/WinSW.Tasks/WinSW.Tasks.csproj b/src/WinSW.Tasks/WinSW.Tasks.csproj new file mode 100644 index 0000000..3c588e4 --- /dev/null +++ b/src/WinSW.Tasks/WinSW.Tasks.csproj @@ -0,0 +1,14 @@ + + + + net461 + latest + true + + + + + + + + diff --git a/src/WinSW.Tests/MetadataTests.cs b/src/WinSW.Tests/MetadataTests.cs new file mode 100644 index 0000000..da65691 --- /dev/null +++ b/src/WinSW.Tests/MetadataTests.cs @@ -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 diff --git a/src/WinSW.Tests/WinSW.Tests.csproj b/src/WinSW.Tests/WinSW.Tests.csproj index a1ba394..1abc76a 100644 --- a/src/WinSW.Tests/WinSW.Tests.csproj +++ b/src/WinSW.Tests/WinSW.Tests.csproj @@ -19,6 +19,7 @@ + diff --git a/src/WinSW.sln b/src/WinSW.sln index 9b3287d..c22c576 100644 --- a/src/WinSW.sln +++ b/src/WinSW.sln @@ -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 diff --git a/src/WinSW/WinSW.csproj b/src/WinSW/WinSW.csproj index ff835f5..f3e8189 100644 --- a/src/WinSW/WinSW.csproj +++ b/src/WinSW/WinSW.csproj @@ -37,6 +37,10 @@ + + + + @@ -64,6 +68,11 @@ $(InputAssemblies) "$(OutDir)WinSW.Plugins.dll" $(InputAssemblies) "$(OutDir)log4net.dll" $(InputAssemblies) "$(OutDir)System.CommandLine.dll" + $(InputAssemblies) "$(OutDir)System.Buffers.dll" + $(InputAssemblies) "$(OutDir)System.Memory.dll" + $(InputAssemblies) "$(OutDir)System.Numerics.Vectors.dll" + $(InputAssemblies) "$(OutDir)System.Runtime.CompilerServices.Unsafe.dll" + $(InputAssemblies) "$(OutDir)System.ValueTuple.dll" "$(ArtifactsDir)WinSW.$(TargetFrameworkSuffix).exe" @@ -74,9 +83,13 @@ - + + + + +