DEV Community

jeikabu
jeikabu

Posted on • Originally published at rendered-obsolete.github.io on

Nupkg Containing Native Libraries

Recently started looking at publishing our C# libraries to nuget.org. This first post covers my experience with the actual packaging. In a later post I’ll do the signing and publishing.

In the Beginning

Subor.NNanomsg.NETStandard (our fork of NNanomsg- a C# library for nanomsg) was particularly frustrating because it involves a native library nanomsg.dll.

Google un-earthed several promising resources:

But I struggled making a package that worked; nanomsg.dll wasn’t in the output directory.

General Tips

The .targets file mentioned in several places seems to no longer be necessary (VS 15.7.4 and nuget.exe 4.7.0) unless your package will be consumed by c++ projects.

Managed libraries need to get packaged in /lib/TFM/. SeeSupporting multiple .NET framework versions and about Target Framework Monikers (TFM)

Native libraries need to get packaged in /runtimes/RID/native/. Runtime ID Catalog not only has a complete list of all Runtime IDs (RIDs), but also gives a pretty detailed explanation.

  • Familiarize yourself with nuget.exe
    • nuget pack -Properties Configuration=Release will build a release nupkg (default is debug) for the .csproj in the current directory. The output assembly will automatically be included.
    • Package version can be set by adding -Version X.Y.Z
  • The NuGetPackageExplorer gives a nice visual look at your nupkg and its meta-data. Just make sure to File->Close otherwise nuget.exe and Visual Studio will have problems accessing your nupkg.

Nuspec

  • nuget.exe spec will generate a template nuspec from csproj in current directory
  • A nuspec file with the same name as the csproj will automatically get included when using nuget.exe from the command line. For example, NNanomsg.NETStandard.csproj and NNanomsg.NETStandard.nuspec.
  • Replacement tokens usable in nuspec
  • Using a nuspec together with a csproj is clumsy
    • There’s only replacement tokens for some meta-data values
    • Omitting a tag from the nuspec results in the value being undefined- even if it is set in the csproj
    • Enabling generation of NuGet package on build (placed in output folder) doesn’t use the nuspec:

When using nuget.exe, a <files> section of the nuspec seems to be the only way to include /runtimes/ files. <Content> in csproj places things in a content/ subfolder (nuget.exe ignores <ContentTargetFolders>), <None> doesn’t include them at all.

  • You can directly pack the nuspec (e.g. nuget pack NNanomsg.NETStandard.nuspec)
    • If you see the following warning:
  WARNING: NU5100: The assembly 'bin\Release\netstandard2.0\NNanomsg.NETStandard.dll' is not inside the 'lib' folder and hence it won't be added as a reference when the package is installed into a project. Move it into the 'lib' folder if it needs to be referenced.

Enter fullscreen mode Exit fullscreen mode

You likely need the following in your nuspec:

  <files>
      <file src="bin\$configuration$\netstandard2.0\*.dll" target="lib\netstandard2.0\"/>
      <file src="runtimes\**" target="runtimes/"/>
  </files>

Enter fullscreen mode Exit fullscreen mode
  • If you get the following error:
  Attempting to build package from 'NNanomsg.NETStandard.nuspec'.
  Value cannot be null or an empty string.
  Parameter name: value

Enter fullscreen mode Exit fullscreen mode

The nuspec contains a replacement token (i.e. $xxx$) that needs to be replaced with an actual value

NuGet as MSBuild targets

Starting NuGet 4.0, all package-related metadata can be stored in the csproj.

If your project doesn’t reference any external packages you might need to force the PackageReference format by adding to your csproj:

<PropertyGroup>
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>

Enter fullscreen mode Exit fullscreen mode

Not sure if it matters, but I use PackageReference by default ( Tools->Options->NuGet Package Manager ):

I include the native binaries with:

<ItemGroup>
    <Content Include="runtimes\**" PackagePath="runtimes" Visible="false" />
</ItemGroup>

Enter fullscreen mode Exit fullscreen mode

And then right-click the project->Pack to generate the nupkg. Or in a VS Developer Command Prompt:

msbuild /t:pack

Enter fullscreen mode Exit fullscreen mode

Consuming nupkg

In Visual Studio, Tools->Options->NuGet Package Manager->Package Sources to add a local directory as source for nuget packages:

Visual Studio Package Manager ( View->Other Windows->Package Manager Console ) makes it easy to reload a local nupkg. Make sure Default project is set to the correct project and run: Install-Package D:\dev\NNanomsg\NNanomsg.NETStandard\NNanomsg.NETStandard.0.5.2.nupkg.

Installing the package doesn’t cause the native binaries to get copied, you have to build the project.

Assuming your nupkg contains 32-bit and 64-bit native libraries, runtimes/win-x86/native/nanomsg.dll and runtimes/win-x64/native/nanomsg.dll, respectively. If Platform target (project Properties->Build ) of the consuming project is Any CPU neither native assembly will be copied to the output directory. You must select either x86 or x64:

Conclusions

  • Least frustrating to pick either nuspec or VS project for package definition- don’t use both
  • Nuspec has diminished VS integration, but simpler command line use- just need nuget.exe
  • Using VS project for package definition has best VS integration, but then stuck dealing with complexities of msbuild

Next I’ll go over signing our package and pushing it to nuget.org.

Top comments (0)