.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

232 lines
13 KiB

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<!-- RIDs we publish the app for. Declared here (not solution-wide) so the lock
file stays in sync for these targets without forcing per-RID restore onto
the ILSpyCmd tool (PackAsTool + GeneratePackageOnBuild) or the test projects. -->
<RuntimeIdentifiers>win-x64;win-arm64;linux-x64;osx-arm64</RuntimeIdentifiers>
<!-- Framework-dependent publishes target net10.0; roll forward to a newer major runtime when
the exact one isn't installed so the app still starts on machines that only have a later
.NET. -->
<RollForward>major</RollForward>
<Nullable>enable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Assets/ILSpy-Large.ico</ApplicationIcon>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<RootNamespace>ICSharpCode.ILSpy</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Properties/AssemblyInfo.cs sets [assembly: AssemblyVersion(...)] from
DecompilerVersionInfo (which the build pipeline rewrites with the live
git revision). The SDK auto-generated AssemblyInfo would overwrite those
with whatever <Version> resolves to in the project, defeating the dynamic
version injection. -->
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<!-- ILSpy uses System.Composition with attribute-driven discovery; MEF002 nudges toward
code-based DI which doesn't apply. MEF004 wants an explicit Shared/NonShared marker, but
System.Composition has no [NonShared] attribute (the absence of [Shared] *is* the
non-shared semantic), so it is a false positive on every Options panel viewmodel.
CA1001/CA2213 fire because tab-page models hold a CancellationTokenSource that lives as
long as the document dock, which is intentional. -->
<NoWarn>$(NoWarn);MEF002;MEF004;CA1001;CA2213</NoWarn>
<!-- Server GC: spawns one GC heap per CPU core and runs collections on dedicated
GC threads, which keeps the UI thread responsive when background work
allocates aggressively. Workstation GC (the default) would pause the UI
thread on every Gen-1/2 collection caused by allocations on ANY thread.
Concurrent stays on (the default) so even server collections don't
stop-the-world for long. -->
<ServerGarbageCollection>true</ServerGarbageCollection>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
<!-- DATAS: let server GC scale its heap count to the live load instead of pinning one heap
per core, trading a little throughput for a much smaller idle working set. -->
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
</PropertyGroup>
<!-- Trap arithmetic overflow/underflow in Debug builds so off-by-one bugs surface as exceptions
during development instead of silently wrapping. -->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Remove="Assets\ILSpy-Large.ico" />
<AvaloniaResource Remove="Assets\ILSpy.pdn" />
<!-- macOS bundle inputs: copied into ILSpy.app at publish-time by BuildMacAppBundle.
Excluded from avares:// because they're consumed by the OS loader, not the app. -->
<AvaloniaResource Remove="Assets\ILSpy.icns" />
<AvaloniaResource Remove="Assets\macos\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TextView\*.xshd" />
<EmbeddedResource Include="..\doc\ILSpyAboutPage.txt">
<LogicalName>ILSpyAboutPage.txt</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\doc\third-party-notices.txt">
<LogicalName>third-party-notices.txt</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\LICENSE">
<LogicalName>license.txt</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<!-- Avalonia core -->
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.Desktop" />
<PackageReference Include="Avalonia.Themes.Simple" />
<PackageReference Include="Svg.Controls.Skia.Avalonia" />
<!-- Avalonia 12 DevTools: the in-app bridge half. Pairs with the AvaloniaUI.DeveloperTools
global tool (the inspector UI process) that connects over this bridge. DEBUG-only: the
assets are dropped in Release so nothing diagnostic ships. The matching WithDeveloperTools
and AttachDeveloperTools calls live in Program.cs / App.axaml.cs, also under #if DEBUG. -->
<PackageReference Include="AvaloniaUI.DiagnosticsSupport">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<!-- Editor, docking, grid, behaviors -->
<PackageReference Include="Avalonia.AvaloniaEdit" />
<PackageReference Include="AvaloniaEdit.TextMate" />
<PackageReference Include="Xaml.Behaviors.Avalonia" />
<PackageReference Include="Dock.Avalonia" />
<PackageReference Include="Dock.Avalonia.Themes.Simple" />
<PackageReference Include="Dock.Controls.Recycling" />
<PackageReference Include="Dock.Model.Mvvm" />
<PackageReference Include="Dock.Serializer.SystemTextJson" />
<PackageReference Include="ProDataGrid" />
<!-- MVVM, DI, MEF -->
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="System.Composition.AttributedModel" />
<PackageReference Include="System.Composition.Hosting" />
<PackageReference Include="System.Composition.TypedParts" />
<!-- NRBF decoder for the ImageList resource viewer — first-party Microsoft MIT
package, netstandard2.0+, parses BinaryFormatter-shape payloads without
instantiating the contained types. Lets us decode
System.Windows.Forms.ImageListStreamer blobs on Linux/macOS without
referencing WinForms. -->
<PackageReference Include="System.Formats.Nrbf" />
<!-- CLI parsing -->
<PackageReference Include="McMaster.Extensions.CommandLineUtils" />
<!-- NuGet V3 feed client for the "Open from NuGet feed" dialog: search, version
enumeration, and download into the global packages folder. -->
<PackageReference Include="NuGet.Protocol" />
<!-- Parses/validates target-framework monikers for the "Set Target Framework" dialog. -->
<PackageReference Include="NuGet.Frameworks" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.ILSpyX\ICSharpCode.ILSpyX.csproj" />
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
<ProjectReference Include="..\ICSharpCode.BamlDecompiler\ICSharpCode.BamlDecompiler.csproj" />
</ItemGroup>
<!-- DEBUG-only Pdb2Xml command requires Microsoft.DiaSymReader, which uses native COM
interop and is Windows-only AT RUNTIME. The packages are referenced on every build host
(Debug only) so that restore produces an identical packages.lock.json regardless of OS;
a Windows-host-gated reference makes the lock diverge between Windows and Linux restores.
The consuming command file is still gated by DEBUG and WINDOWS, so on non-Windows the
packages are restored but unused. -->
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" />
<PackageReference Include="Microsoft.DiaSymReader" />
<PackageReference Include="Microsoft.DiaSymReader.Native" />
</ItemGroup>
<!-- The Debug Steps pane is a DEBUG-only diagnostic. The code-behind and viewmodel
are wrapped in `#if DEBUG`, so the C# type vanishes under Release; but Avalonia
compiles every .axaml file regardless of preprocessor state, and the XamlIl
compiler then fails resolving x:Class="ICSharpCode.ILSpy.Views.DebugSteps". Removing the
AXAML from the build under non-Debug configurations matches the C# gating. -->
<ItemGroup Condition="'$(Configuration)' != 'Debug'">
<AvaloniaXaml Remove="Views\DebugSteps.axaml" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug' AND $([MSBuild]::IsOSPlatform('Windows'))">
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
</PropertyGroup>
<!-- macOS .app bundle.
The Avalonia Window.Icon property doesn't reach the Dock on macOS; the Dock
reads CFBundleIconFile from Info.plist and loads <name>.icns from Resources/.
Bundle layout under bin/<config>/<tfm>/<rid>/:
ILSpy.app/Contents/Info.plist
ILSpy.app/Contents/MacOS/<published files, with apphost made executable>
ILSpy.app/Contents/Resources/ILSpy.icns
Trigger: any osx-* RuntimeIdentifier after the standard Publish target. -->
<Target Name="BuildMacAppBundle"
AfterTargets="Publish"
Condition="$(RuntimeIdentifier.StartsWith('osx-'))">
<PropertyGroup>
<_MacBundleRoot>$([System.IO.Path]::GetFullPath('$(PublishDir)..'))/$(AssemblyName).app</_MacBundleRoot>
<_MacBundleContents>$(_MacBundleRoot)/Contents</_MacBundleContents>
</PropertyGroup>
<ItemGroup>
<_MacPublishFiles Include="$(PublishDir)**/*" />
</ItemGroup>
<RemoveDir Directories="$(_MacBundleRoot)" />
<MakeDir Directories="$(_MacBundleContents);$(_MacBundleContents)/MacOS;$(_MacBundleContents)/Resources" />
<Copy SourceFiles="@(_MacPublishFiles)"
DestinationFiles="@(_MacPublishFiles->'$(_MacBundleContents)/MacOS/%(RecursiveDir)%(Filename)%(Extension)')" />
<Copy SourceFiles="$(MSBuildProjectDirectory)/Assets/ILSpy.icns"
DestinationFolder="$(_MacBundleContents)/Resources" />
<Copy SourceFiles="$(MSBuildProjectDirectory)/Assets/macos/Info.plist"
DestinationFolder="$(_MacBundleContents)" />
<Exec Command="chmod +x &quot;$(_MacBundleContents)/MacOS/$(AssemblyName)&quot;"
Condition="!$([MSBuild]::IsOSPlatform('Windows'))" />
<Message Importance="high" Text="macOS bundle written to $(_MacBundleRoot)" />
</Target>
<!-- Locate the installed MSVC tools so ApplyStackExtension below can find editbin.exe. The props
file the import pulls in defines $(VCToolsVersion); it only exists when building under VS /
a Developer environment on Windows, so $(VCToolsVersion) stays empty everywhere else and the
stack-extension target is skipped. -->
<PropertyGroup>
<VCToolsVersionPropsFileNameDefault>Microsoft.VCToolsVersion.default.props</VCToolsVersionPropsFileNameDefault>
<VCBasePath>$(MSBuildToolsPath)\..\..\..\VC\</VCBasePath>
<!-- In VS 2022 there is an extra directory level that's why we need to add one more '..' -->
<VCBasePath Condition="!Exists('$(VCBasePath)Auxiliary\Build\$(VCToolsVersionPropsFileNameDefault)')">$(MSBuildToolsPath)\..\..\..\..\VC\</VCBasePath>
<VCToolsVersionPropsFile>$(VCBasePath)Auxiliary\Build\$(VCToolsVersionPropsFileNameDefault)</VCToolsVersionPropsFile>
</PropertyGroup>
<Import Project="$(VCToolsVersionPropsFile)" Condition="Exists('$(VCToolsVersionPropsFile)')" />
<ItemGroup>
<SortResXInput Include="Properties\*.resx" />
<SortResXInput Include="..\ILSpy.ReadyToRun\Properties\*.resx" />
<SortResXStamp Include="obj\sort-resx.stamp" />
</ItemGroup>
<!-- Keep .resx entries sorted by name so localisation diffs stay clean. Local Windows builds
only (the command is empty otherwise) and skipped on CI; the stamp makes it incremental. -->
<Target Name="SortResX" BeforeTargets="BeforeBuild" Inputs="@(SortResXInput)" Outputs="@(SortResXStamp)" Condition="'$(GITHUB_ACTIONS)' != 'true'">
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
<SortResX>powershell -NoProfile -ExecutionPolicy Bypass -File BuildTools/sort-resx.ps1</SortResX>
</PropertyGroup>
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
<SortResX>pwsh -NoProfile -ExecutionPolicy Bypass -File BuildTools/sort-resx.ps1</SortResX>
</PropertyGroup>
<Exec WorkingDirectory=".." Command="$(SortResX)" Timeout="60000" Condition="'$(SortResX)' != ''" />
<Touch Files="@(SortResXStamp)" AlwaysCreate="true" Condition="'$(SortResX)' != ''" />
</Target>
<!-- Deeply nested types / expressions can drive the IL+AST transforms into recursion deep
enough to overflow the default 1 MB main-thread stack. On Windows the managed runtime
can't grow the main thread's stack at run time, so (as in the WPF build) editbin rewrites
the apphost's PE stack-reserve header to 16 MB. Gated on the MSVC tools being present
($(VCToolsVersion) is empty outside a VS / Developer environment), so it is a no-op on
Linux/macOS CI and any non-MSVC Windows build. EXIT 0 keeps editbin warnings from failing
the build. -->
<Target Name="ApplyStackExtension" AfterTargets="PostBuildEvent" Condition="'$(VCToolsVersion)'!=''">
<Exec Command="&quot;$(VCBasePath)Tools\MSVC\$(VCToolsVersion)\bin\Hostx64\x64\editbin.exe&quot; /stack:16777216 &quot;$(TargetDir)$(TargetName).exe&quot;&#xD;&#xA;EXIT 0" />
</Target>
</Project>