Search code examples
c#visual-studiomsbuildnuget

Include pdb files into my nuget (nupkg) files


I am using MSBuild to generate my nuget packages.

Is there any command I need to set, to allow it to include my .pdb files, for stepping into the source while debugging?

I do not want the source files to be included into the project that is pulling in the nuget package.


Solution

  • Producing

    Simplest way of configuring is to have a Directory.Build.props with the common parameters something like this...

    <Project>
      <PropertyGroup>
        <!-- Based on https://devblogs.microsoft.com/dotnet/producing-packages-with-source-link/ -->
        <!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
        <PublishRepositoryUrl>true</PublishRepositoryUrl>
    
        <!-- Embed source files that are not tracked by the source control manager in the PDB -->
        <EmbedUntrackedSources>true</EmbedUntrackedSources>
    
        <!-- Embed symbols containing Source Link in the main file (exe/dll) -->
        <DebugType>embedded</DebugType>
      </PropertyGroup>
    
      <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
        <GenerateDocumentationFile>true</GenerateDocumentationFile>
      </PropertyGroup>
    
      <PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
        <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
      </PropertyGroup>
    <Project>
    

    In each project that produces a package you can then reference the appropriate SourceLink assembly for your system.

    Explaination as follows:

    • ContinuousIntegrationBuild: Causes your CI system to produce canonical paths to files, should only be set for CI server as otherwise you won't be able to find local sources DebugType
    • GeneratedDocumentationFile: Generates the XML documentation file for inclusion with the dll - you do write docs don't you ;-)
    • Embedded: Adds the pdb data to the assembly file, simplifies distribution at the cost of increasing your dll size

    More information at this MS blog article

    Consuming

    NET 7

    Copying the symbol files to the execution directory is now incorporated in the NET 7.0 SDK/VS2022 17.4+ as an opt-in approach. Add the following fragment to your project file...

    <PropertyGroup>
      ...
      <CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
      <CopyDocumentationFilesFromPackages>true</CopyDocumentationFilesFromPackages>
    </PropertyGroup>
    

    This will copy all symbols and documentation files into your output directory; if you only want a subset, e.g. your files, you will have to implement a filtering mechanism on top of this

    Earlier

    If you are using VS2017 15.4 or later, you can define a MSBuild property in your project file

    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
    

    This is discussed in NuGet #4142

    However, there is still an issue as the new project system does not copy the pdbs from packages to the bin/publish folder for .NET Core 3.0+, a good summary is also at sourcelink/#628

    As the fix is only supported in the .NET 7 SDK+, you will need a work-around which is to include the following fragment into API and test projects to ensure you have the appropriate pdbs to allow you to step into the remote source code.

    <!-- https://github.com/dotnet/sdk/issues/1458#issuecomment-1063915490 -->
    <Target Name="IncludeSymbolFiles" AfterTargets="ResolveAssemblyReferences" Condition="@(ReferenceCopyLocalPaths) != ''">
      <ItemGroup>
        <ReferenceCopyLocalPaths Include="%(ReferenceCopyLocalPaths.RelativeDir)%(ReferenceCopyLocalPaths.Filename).pdb;                                %(ReferenceCopyLocalPaths.RelativeDir)%(ReferenceCopyLocalPaths.Filename).xml" />
        <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="!Exists('%(FullPath)')" />
      </ItemGroup>
    </Target>