Core: dotnet core 3.0 doesn't copy symbol files(*.pdb) and xml document files from nuget package to bin/publish folder.

Created on 10 Oct 2019  路  10Comments  路  Source: dotnet/core

Recently I upgrade my dotnet core sdk from 2.1 to 3.0, and I find this issue:

dotnet core 3.0 doesn't copy symbol files(*.pdb) and xml document files from nuget packages to bin/publish folder. Neither build nor publish command do this. For example, I have a project A, it references nuget package B, B has 3 files, B.dll, B.pdb and B.xml, after building, I can not find B.xml and B.pdb in the bin folder, but I really need them.

pdb and xml files are important to me to track the program's issues, even in production environment. I wonder if there is a switch to turn this feature on. Is this a bug?

Most helpful comment

Is there any investigation/work done here or on dotnet/sdk#1458 or somewhere else this is tracked as in progress?

All 10 comments

@livarcocc

It's a big mistake and issue for PROD support....

@livarcocc @nguerrera can you help with this issue?

This used to do the trick, not anymore:

  <Target Name="_ResolvePublishNuGetPackagePdbsAndXml" AfterTargets="RunResolvePublishAssemblies">
    <ItemGroup>
      <ResolvedFileToPublish Include="@(ResolvedAssembliesToPublish->'%(RootDir)%(Directory)%(Filename).pdb')" RelativePath="$([System.IO.Path]::ChangeExtension(%(ResolvedAssembliesToPublish.DestinationSubPath), '.pdb'))" DestinationSubPath="$([System.IO.Path]::ChangeExtension(%(ResolvedAssembliesToPublish.DestinationSubPath), '.pdb'))" Condition="'%(ResolvedAssembliesToPublish.PackageName)' != ''&#xD;&#xA;                    and Exists('%(RootDir)%(Directory)%(Filename).pdb')" />
    </ItemGroup>
  </Target>

Is there any investigation/work done here or on dotnet/sdk#1458 or somewhere else this is tracked as in progress?

This is important to us as well. We can continue to write work-arounds for this using scripting, but we would prefer that the pdb's and docs that we packed into the our custom NuGets land in the main apps output directory. Its causing some headaches with our build system.

@jtbrower Could you please paste your script here?

@guogangj Currently, I manage ~13 repos with over 120 NuGet packages that we publish privately to be consumed by our NetCore services and NetCore Desktop apps. My scripting covers many aspects including signing all dlls and NuGet packages. As a result, my approach is probably overly complex for most situations, but it might serve as inspiration to other unique approaches.

Our defined Problem is related only to NuGet packages that we have full control over; that is, we need the PDBs that are published with our own _.nupk's_, to be located in all of our executable's bin directories, spread over many repos. Since our issue relates only to our own symbol files, our solution does not care for third party symbols. Our solution is precise in that it does not copy a PDB that is not needed by a particular exe, nor will it copy over the top of an existing PDB.

Solution Summary We start by making the symbol files easier to access; for each repo, assure that its own PDB's are copied to a common output dir at the root of each repo. Then after all repo's are built, copy every PDB from every repo into the current builds common PDB directory. Finally using that common directory, assure that all exes have a copy of the required symbols.

I use a similar approach to assure that I can reach the bin/obj/ext files for every project at the root of each repo.

Step 1 to make relevant symbols easier to access inside each repo, I created a file called _CopyPdb.Build.targets_ with the following content. Every top level _Directory.Build.targets_ file in all repos import this file.

<Project>
  <!-- 
         Place a copy of the symbols into an easy to reach location. After the repo has
         been built this location will hold a PDB for every project in its own repo. 
   -->
  <Target Name="CopyPdbToSharedLocation" AfterTargets="Build">
    <Copy SourceFiles="$(OutputPath)$(AssemblyName).pdb"
               DestinationFolder="$(SolutionDir).pdb\" />
  </Target>
</Project>

Step 2 I have a master build script that builds every repo, takes care of code signing, zipping files, testing and ect. As this script is walking those repos and performing each build, it will make a copy of the PDB's created in the prior step by placing them in our build output folder. This build output folder is unique to each build and is identified by a SemVersion. After all 13 of our repositories are built, this folder will contain the latest copy of PDB from every project we maintain.

Note that the $repoPath is pointing at the current repo in our build loop and the currentBuildPdbDir is pointing at a directory where every PDB for the current build is kept.

#$repoPath is pointing at the current repo in our build loop

#currentBuildPdbDir is a directory that at the end of the build will contain a copy of
#every PDB file for all projects we manage.
Copy-Item -Recurse -ErrorAction Stop -Force `
          -Path "$repoPath\.pdb\*" `
          -Destination "$currentBuildPdbDir\"

Step 3 after our build script has built every repo, it calls the following PowerShell function.
```

#

# There is an issue with NuGet Package Manager where PDBs
# inside NuGet packages, do not get copied to the output directory of the
# target build assembly. So through our build system we have pushed all .pdb
# debug symbols into a directory that we recurse through comparing with the
# contents of the EXE's final output directory to see if the PDB is missing
# but the assembly is present. If that is the case we copy the PDF to the
# exe directory.
##############################################################################
function Copy-PdbToExeDirs {
Param(
#For us, this directory is pointing to a location inside of the
#current build output folder. It contains a copy of every PDB
#file for every project accross all of our repos.
[string]$PdbDir,
#This is an array of directory paths that point to the locations
#of every executable that we build accross all of our repos.
#Like the PdbDir, this location is inside the current builds
#output folder such as /BuildArtifacts/$SemVersion/.../
[string[]]$TargetDirs
)
#loop through all symbol files that are located in the PDbDir
Get-ChildItem -Path $PdbDir | ForEach-Object {

  $pdbFileName = "$($_.BaseName).pdb"
  $dllFileName = "$($_.BaseName).dll"

  #check each built exe to see if it contains a dll that
  #matches the symbol file but is missing the symol file
  foreach ($trgtDir in $TargetDirs) {
    $pdbPath = "$trgtDir\$pdbFileName"
    $dllPath = "$trgtDir\$dllFileName"

    #If exe output dir does not contain the dll that matches
    #the current symbol file in the outer loop, then we don't
    #need to copy the pdb.
    if ($false -eq (Test-Path $dllPath)) {
      continue
    }

    #See if the pdb file is missing.  This is the case
    #for most dlls because NuGet will not copy the pdb
    #to output directory, especially true for transitive.
    #If it already exists, then NuGet might have fixed
    #this problem or the build was not cleaned. Don't
    #copy over the top of it.
    if ($false -eq (Test-Path $pdbPath)) {
      Write-Status "Copy $pdbFileName to $trgtDir"
      Copy-Item $_.FullName "$trgtDir\"
    }
  }
}

}

```

Likely dup of https://github.com/dotnet/sdk/issues/1458 @carlossanlop

Confirmed as duplicate. Please move the conversation to dotnet/sdk#1458.

Was this page helpful?
0 / 5 - 0 ratings