I am building a tool package which depends on another NuGet package. As it is not an usual library, it must include all dependencies into the tools\
directory. I have the following csproj
(only the relevant bits are shown):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DevelopmentDependency>true</DevelopmentDependency>
<IsTool>true</IsTool>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="16.7.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.7.0" PrivateAssets="all" />
<PackageReference Include="System.Text.Json" Version="4.7.2" PrivateAssets="all" GeneratePathProperty="true" />
</ItemGroup>
<ItemGroup>
<None Include="build\*" Pack="true" PackagePath="build\" />
<None Include="$(PkgSystem_Text_Json)\lib\netstandard2.0\*.dll" Visible="false" Pack="true" PackagePath="tools\" />
</ItemGroup>
</Project>
So I used GeneratePathProperty
on my dependency and try to include the assembly using generated path $(PkgSystem_Text_Json)
. I can confirm that the path is correct by setting Visible="true"
and inspecting my project. But the assembly is missing from my NuGet package. Seems that the generated path property does not exist at the moment of packaging. If I use an absolute path the assembly gets included but this solution is not portable.
How do I make generated path property work at packaging stage?
I got it to work locally by using
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<Target Name="_PackLocalLockFileAssemblies" AfterTargets="ResolveLockFileCopyLocalFiles">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths)" />
</ItemGroup>
</Target>
CopyLocalLockFileAssemblies
is a trick to get the PackageReference
DLLs into the bin folder. The files to-be-copied get resolved into ReferenceCopyLocalPaths
items in the ResolvelockFileCopyLocalFiles
target. The new target takes those resolved reference paths and adds them as BuildOutputInPackage
items, that the GenerateNuSpec
target takes as the input.
This also takes care of all the transitive dependencies.