diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 836cd9b..3bc1125 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -36,6 +36,12 @@ jobs: - name: Build (CD) if: ${{ github.event.inputs.version != '' }} run: dotnet build src/bflat/bflat.csproj -t:BuildLayouts -c:Release -p:Version=${{ github.event.inputs.version }} + - name: Debloat the libs + run: | + dotnet run --project src/debloat/debloat.csproj layouts/windows-x64/lib + dotnet run --project src/debloat/debloat.csproj layouts/windows-arm64/lib + dotnet run --project src/debloat/debloat.csproj layouts/linux-glibc-x64/lib + dotnet run --project src/debloat/debloat.csproj layouts/linux-glibc-arm64/lib - name: Prepare symbols run: | mv layouts/windows-x64/bflat.pdb layouts/obj/windows-x64/ diff --git a/src/bflat/BuildCommand.cs b/src/bflat/BuildCommand.cs index 5dc4734..05e4b86 100644 --- a/src/bflat/BuildCommand.cs +++ b/src/bflat/BuildCommand.cs @@ -350,13 +350,18 @@ public override int Handle(ParseResult result) { char separator = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':'; + string currentLibPath = Path.Combine(homePath, "lib"); + + libPath = currentLibPath; + string osPart = targetOS switch { - TargetOS.Linux when libc == "bionic" => "linux-bionic", - TargetOS.Linux => "linux-glibc", + TargetOS.Linux => "linux", TargetOS.Windows => "windows", _ => throw new Exception(targetOS.ToString()), }; + currentLibPath = Path.Combine(currentLibPath, osPart); + libPath = currentLibPath + separator + libPath; string archPart = targetArchitecture switch { @@ -364,15 +369,20 @@ public override int Handle(ParseResult result) TargetArchitecture.X64 => "x64", _ => throw new Exception(targetArchitecture.ToString()), }; + currentLibPath = Path.Combine(currentLibPath, archPart); + libPath = currentLibPath + separator + libPath; - string osArchPath = Path.Combine(homePath, "lib", $"{osPart}-{archPart}"); - if (!Directory.Exists(osArchPath)) + if (targetOS == TargetOS.Linux) { - Console.Error.WriteLine($"Directory '{osArchPath}' doesn't exist."); - return 1; + currentLibPath = Path.Combine(currentLibPath, libc ?? "glibc"); + libPath = currentLibPath + separator + libPath; } - libPath = String.Concat(osArchPath, separator.ToString(), Path.Combine(homePath, "lib")); + if (!Directory.Exists(currentLibPath)) + { + Console.Error.WriteLine($"Directory '{currentLibPath}' doesn't exist."); + return 1; + } } if (!bare) diff --git a/src/bflat/bflat.csproj b/src/bflat/bflat.csproj index 1ee1145..c4b9084 100644 --- a/src/bflat/bflat.csproj +++ b/src/bflat/bflat.csproj @@ -13,7 +13,7 @@ 7.0.0-rtm.22529.1 https://github.com/bflattened/runtime/releases/download/ - 1.2 + 1.3 https://github.com/bflattened/blobs/releases/download/ 4.4.0-1.final @@ -62,11 +62,21 @@ - - - - - + + windows\x64\ + + + windows\arm64\ + + + linux\x64\glibc\ + + + linux\arm64\glibc + + + linux\arm64\bionic + @@ -146,7 +156,7 @@ Outputs="@(SupportedTarget->'$(IntermediateOutputPath)\bflat-libs-%(Identity)-$(RuntimeVersion).semaphore')"> + DestinationFolder="$(OutputPath)lib\%(SupportedTarget.LibPath)" /> diff --git a/src/debloat/Program.cs b/src/debloat/Program.cs new file mode 100644 index 0000000..12dbe59 --- /dev/null +++ b/src/debloat/Program.cs @@ -0,0 +1,94 @@ +// bflat C# compiler +// Copyright (C) 2021-2022 Michal Strehovsky +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +Merge(args[0]); + +static void Merge(string directory) +{ + foreach (string subDirectory in Directory.EnumerateDirectories(directory)) + Merge(subDirectory); + + Dictionary> candidates = new Dictionary>(); + int expectedFiles = 0; + foreach (string subDirectory in Directory.EnumerateDirectories(directory)) + { + expectedFiles++; + foreach (var f in Directory.EnumerateFiles(subDirectory, "*.dll")) + { + string key = Path.GetFileName(f); + if (!candidates.TryGetValue(key, out List list)) + candidates.Add(key, list = new List()); + list.Add(f); + } + } + + foreach (var maybeSameFiles in candidates.Values) + { + if (maybeSameFiles.Count != expectedFiles) + continue; + + bool allSame = true; + ReadOnlySpan expected = SanitizedAssemblyBytes(maybeSameFiles[0]); + for (int i = 1; i < maybeSameFiles.Count; i++) + { + ReadOnlySpan actual = SanitizedAssemblyBytes(maybeSameFiles[i]); + if (!expected.SequenceEqual(actual)) + { + allSame = false; + break; + } + } + + if (allSame) + { + File.Move(maybeSameFiles[0], Path.Combine(directory, Path.GetFileName(maybeSameFiles[0]))); + string pdbFile = Path.ChangeExtension(maybeSameFiles[0], "pdb"); + if (File.Exists(pdbFile)) + File.Move(pdbFile, Path.Combine(directory, Path.GetFileName(pdbFile))); + + for (int i = 1; i < maybeSameFiles.Count; i++) + { + File.Delete(maybeSameFiles[i]); + pdbFile = Path.ChangeExtension(maybeSameFiles[i], "pdb"); + if (File.Exists(pdbFile)) + File.Delete(pdbFile); + } + } + } +} + +static byte[] SanitizedAssemblyBytes(string fileName) +{ + byte[] b = File.ReadAllBytes(fileName); + Span span = b; + PEReader perdr = new PEReader(ImmutableArray.Create(b)); + span.Slice(perdr.PEHeaders.CoffHeaderStartOffset + 4, 4).Clear(); + MetadataReader mdrdr = perdr.GetMetadataReader(); + Guid mvid = mdrdr.GetGuid(mdrdr.GetModuleDefinition().Mvid); + span.Slice(span.IndexOf(mvid.ToByteArray()), 16).Clear(); + foreach (var ddentry in perdr.ReadDebugDirectory()) + span.Slice(ddentry.DataPointer, ddentry.DataSize).Clear(); + if (perdr.PEHeaders.TryGetDirectoryOffset(perdr.PEHeaders.PEHeader.DebugTableDirectory, out int debugDir)) + span.Slice(debugDir, perdr.PEHeaders.PEHeader.DebugTableDirectory.Size).Clear(); + return b; +} \ No newline at end of file diff --git a/src/debloat/debloat.csproj b/src/debloat/debloat.csproj new file mode 100644 index 0000000..41f1d5a --- /dev/null +++ b/src/debloat/debloat.csproj @@ -0,0 +1,8 @@ + + + + Exe + net6.0 + + +