ReferenceTrimmer

repository·main·Indexed 42 days ago

https://github.com/dfederm/referencetrimmer

A tool to identify and remove unnecessary dependencies from MSBuild projects. It supports C# via Roslyn analysis and C++ via MSVC linker output to flatten build dependency graphs and improve performance. Features include detection of unused project and package references, experimental symbol-based analysis for C#, and integration with MSVC link.exe flags for .vcxproj projects.

Tokens
2.4K
Snippets
7
Records
12
Agent score
3%

What's inside ReferenceTrimmer

  1. How ReferenceTrimmer works for C++ (.vcxproj projects)

    main
    For C++ projects, ReferenceTrimmer enables specific MSVC link.exe flags and then parses the output from the Link MSBuild task. It categorizes these outputs and emits them to both the MSBuild console and a JSON output file. Note that it does not currently issue MSBuild warnings.
  2. How ReferenceTrimmer works for C#

    main

    C# support consists of two components:

    1. MSBuild Task: Collects all references passed to the compiler.
    2. Roslyn Analyzer: Determines which references are actually used and compares them against the references gathered by the Task.

    Detection Methods:

    • Default: Uses the GetUsedAssemblyReferences compiler API (requires Visual Studio 2019 v16.10+ or .NET 5+).
    • Symbol Analysis: If $(ReferenceTrimmerUseSymbolAnalysis) is enabled, the analyzer tracks symbol declarations and code operations to identify which referenced assemblies contain symbols actually used in the code.
  3. Configure C# detection with XML Documentation

    main

    By default, ReferenceTrimmer uses the Roslyn GetUsedAssemblyReferences API. For accurate results, you must enable C# XML documentation generation. If your repository does not already have this enabled, add the following configuration to your Directory.Build.props to enable documentation generation and suppress common XML-related warnings (CS0419, CS1570, CS1573, CS1574, CS1584, CS1591, and SA1602).

      <PropertyGroup>
        <!-- Documentation file generation is required for more accurate C# detection. -->
        <GenerateDocumentationFile>true</GenerateDocumentationFile>
    
        <!-- Suppress XML doc comment issues: 
             - CS0419: Ambiguous reference in cref attribute
             - CS1570: XML comment has badly formed XML
             - CS1573: Parameter has no matching param tag in the XML comment
             - CS1574: XML comment has cref attribute that could not be resolved
             - CS1584: XML comment has syntactically incorrect cref attribute
             - CS1591: Missing XML comment for publicly visible type or member
             - SA1602: Enumeration items should be documented
        -->
        <NoWarn>$(NoWarn);419;1570;1573;1574;1584;1591;SA1602</NoWarn>
      </PropertyGroup>
  4. Disable Windows SDK default libraries in C++

    main

    ReferenceTrimmer may identify unused Windows SDK import libraries. To remove them, modify the <AdditionalDependencies> property in your .vcxproj to include only the specific .lib files your project needs, and ensure you do not include %(AdditionalDependencies) (which pulls in the defaults). If necessary, use <IgnoreSpecificDefaultLibraries> to suppress specific libraries.

    <ItemDefinitionGroup>
      <Link>
        <AdditionalDependencies>kernel32.lib;shlwapi.lib;ws2_32.lib</AdditionalDependencies>
      </Link>
    </ItemDefinitionGroup>
    
    <!-- To ignore specific libraries -->
    <ItemDefinitionGroup>
      <Link>
        <IgnoreSpecificDefaultLibraries>OLDNAMES.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
      </Link>
    </ItemDefinitionGroup>
  5. Suppress ReferenceTrimmer warnings for specific references

    main

    You can disable ReferenceTrimmer warnings for a specific dependency using one of two methods:

    1. Disable a specific rule: Add the warning ID (e.g., RT0002) to the NoWarn metadata attribute of the reference.
    2. Disable all rules for a reference: Add the TreatAsUsed="true" metadata attribute to the reference.
    <!-- Disable a specific rule -->
    <ProjectReference Include="../Other/Project.csproj" NoWarn="RT0002" />
    
    <!-- Disable all rules for this package -->
    <PackageReference Include="SomePackage" TreatAsUsed="true" />
  6. Use ReferenceTrimmer with C++ (.vcxproj) projects

    main

    For C++ projects, ReferenceTrimmer acts as an MSBuild distributed logger. It outputs guidance to the MSBuild stdout stream and writes a ReferenceTrimmerUnusedMSVCLibraries.json.log file to the build working directory.

    Requirements and Usage:

    • Use the -distributedlogger parameter at the MSBuild command line.
    • Use msbuild -restore or msbuild /t:Restore instead of dotnet restore to ensure .vcxproj restore works correctly.
    • The tool enables MSVC link.exe flags /VERBOSE:UNUSEDLIBS and /VERBOSE:UNUSEDDELAYLOAD to identify unused .lib files and delay-load DLLs.
  7. Install ReferenceTrimmer via NuGet

    main

    To use ReferenceTrimmer, add it as a package reference to your projects. For repository-wide application using Central Package Management (CPM), add it as a GlobalPackageReference in your Directory.Packages.props file.

      <ItemGroup>
        <GlobalPackageReference Include="ReferenceTrimmer" Version="{LatestVersion}" />
      </ItemGroup>
  8. Configure ReferenceTrimmer build logic

    main

    Use the $(EnableReferenceTrimmer) property to control whether the ReferenceTrimmer build logic runs for a project. It defaults to true.

    To make ReferenceTrimmer opt-in (instead of always-on), you can set it to false in your Directory.Build.props and then enable it specifically when needed via the MSBuild command line or an environment variable.

    <PropertyGroup>
      <EnableReferenceTrimmer Condition=" '$(EnableReferenceTrimmer)' == '' ">false</EnableReferenceTrimmer>
    </PropertyGroup>

    To enable it via command line:

    msbuild /p:EnableReferenceTrimmer=true
  9. Enable Experimental Symbol-based Analysis for C#

    main

    You can opt into an experimental mode that tracks symbol usage directly instead of relying on GetUsedAssemblyReferences. This mode is more precise for ProjectReference and PackageReference and can detect unused references that the default mode misses (e.g., assemblies used only transitively).

    Key differences:

    • Does not require <GenerateDocumentationFile> (RT0000 will not fire).
    • More precise: only assemblies whose types/members are directly referenced are considered used.
    • Conservative for bare <Reference> items to avoid breaking runtime dependencies.
    • Does not track <see cref> references in XML documentation.
      <PropertyGroup>
        <ReferenceTrimmerUseSymbolAnalysis>true</ReferenceTrimmerUseSymbolAnalysis>
      </PropertyGroup>
  10. Include packages with build files in analysis

    main

    ReferenceTrimmer skips NuGet packages that contain .props or .targets files in their build/ folder by default, as these can influence the build in ways beyond providing compile-time assemblies.

    If you know a package's build files are inconsequential, you can force ReferenceTrimmer to evaluate it by adding the package name to the ReferenceTrimmerIgnorePackageBuildFiles item in your project file or Directory.Build.props.

      <ItemGroup>
        <ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Abstractions" />
      </ItemGroup>
  11. ReferenceTrimmer Warning IDs

    main

    ReferenceTrimmer generates the following warning IDs to identify unnecessary dependencies:

    IdDescription
    RT0000Enable documentation generation for accuracy of used references detection
    RT0001Unnecessary reference
    RT0002Unnecessary project reference
    RT0003Unnecessary package reference
  12. ReferenceTrimmer configuration properties

    main

    ReferenceTrimmer is controlled via several MSBuild properties:

    • $(EnableReferenceTrimmer): Controls whether build logic runs. Defaults to true.
    • $(ReferenceTrimmerEnableVcxproj): Controls whether MSVC link flags are set up to print unused libraries and delay-load DLLs. Defaults to true.
    • $(EnableReferenceTrimmerDiagnostics): When true, writes used and unused reference lists to the intermediate output directory for debugging. Defaults to false.
    • $(ReferenceTrimmerUseSymbolAnalysis): Experimental. When true, uses symbol-based usage detection instead of the default GetUsedAssemblyReferences compiler API. This can detect unused references that the default approach misses (e.g., direct references to assemblies used only transitively). Defaults to false.