How to make a Nuget package for C++

Making a nuget package for managed code is really straightforward, since it is so extensively documented on Microsoft’s various websites.

But if you want to make a nuget package that contains native code like libraries (*.lib), headers (*.h) you are almost out of luck! Microsoft will give you about 3 minuscule paragraphs full of cryptic junk for documentation!

https://docs.microsoft.com/en-us/nuget/guides/native-packages

The first key to understand how to put C++ stuff into a nuget package is to understand that a nuget package (*.nupkg) is really just a zip file that has been renamed. Therefore you should just be able to stick anything in there that you like.

The second key is that we will just be using Nuget to download and unzip the nuget package for us. After that we are on our own.

The third key is that none of the Visual Studio versions will offer any aid at all in hooking up the nuget package to the project that needs it. It is up to you to break open your text editor and modify your visual studio project files (*.vcxproj etc.).

Steps

Here is a high-level summary of what needs to be done, and will be explained in detail:

  1. Gather or stage your native library files into a folder of your choosing.
  2. Create a *.nuspec file in that folder.
  3. Edit the *.nuspec file to include the files you want to include in your package.
  4. Create a *.props file
  5. Call nuget pack to create the package.
  6. Push the nuget package to a feed somewhere.
  7. Create a packages.config file.
  8. Edit the visual studio project file to point to where the restored nuget package is.

NOTE: In this document I will be using the Google Filament renderer library as my demonstration example, since I had to do that here at work recently.

Stage the native files

This should be easy, copy all the files you need for your native library to a a convenient folder. For example:

  • bin/*
  • docs/*
  • include/*
  • lib/*
  • README.md

Create the *.nuspec file

I like to put this *.nuspec file inside of the directory that has the code I’m packaging up. That makes it easier and simplifies the paths we will put inside the *.nuspec file. For my example, mine is filament.nuspec:

  • bin/*
  • docs/*
  • include/*
  • lib/*
  • README.md
  • filament.nuspec

Edit the *.nuspec file

A nuspec files is an xml file and hence must follow the syntax requirements as documented on microsoft’s website:

https://docs.microsoft.com/en-us/nuget/reference/nuspec

I chose to have the package contents follow the same layout as how Google gives them to me. Thus my nuspec package looks like this:

<?xml version="1.0"?>
<package >
	<metadata>
		<id>Google.Filament</id>
		<version>2019.08.08</version>
		<description>Google Filament Renderer</description>
		<tags>Native, native</tags>
	</metadata>
	
	<files>
		<file src="lib\**\*.*"       target="native\lib"     />
		<file src="include\**\*.*"   target="native\include" />
		<file src="docs\*"           target="native\docs"    />
		<file src="bin\*"            target="native\bin"     />
		<file src="README.md"        target="native"      />
		<file src="filament.props"   target="native" />
	</files>
</package>

The most important part here is the <tags> element that contains the text ‘native’. To be doubly sure I got it right, I added it twice, the first time with a capital ‘N’. This is useful when the package is hosted in nuget.org, you can do a search for native packages by using the search term: tag:native

Each <file> xml element has two attributes: a ‘src’ attribute and a ‘target’ attribute. Source is where it gets it’s files from, and Target is where the files will be placed when the nuget package is restored or unzipped. What you specify here is completely up to you. As you can see in my example above, I have also created a filament.props file. I will be using this later to make it simpler for any project to consume this nuget package.

Also I added a root folder called ‘native’. It worked with it, I haven’t tested it without a root folder. But you can give this root folder any arbitrary name you want.

Create a filament.props file

This will aid us later on in consuming the nuget package from another C++ project. Here we will create an MSBuild file (NOT a .vcxproj file) that will describe where the include files and library files are. This step requires a good understanding of the MSBuild xml syntax and especially a good knowledge of C++ project file (i.e. *.vcxproj) syntax. If you don’t know that, just copy and paste my code here:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
        ToolsVersion="15.0">
  <PropertyGroup>
    <LibraryType Condition="'$(Configuration)'=='Debug'">mdd</LibraryType>
    <LibraryType Condition="'$(Configuration)'=='Release'">md</LibraryType>
  </PropertyGroup>
  <ItemGroup>
  <FilamentLibs Include="$(MSBuildThisFileDirectory)\lib\x86_64\$(LibraryType)\*.lib" />
  </ItemGroup>
  <PropertyGroup>
    <!-- Expland the items to a property -->
    <FilamentLibraries>@(FilamentLibs)</FilamentLibraries>
    </PropertyGroup>
    <ItemDefinitionGroup>
    <ClCompile>	<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\include</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <AdditionalDependencies>$(FilamentLibraries);%(AdditionalDependencies) 
      </AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
</Project>

This specifies all the library files using a wildcard pattern (*.lib) and it points to where the include directory is too. It uses the special reserved msbuild property $(MSBuildThisFileDirectory) which helps anchor the paths that are being used inside of this file.

Call Nuget Pack

Now comes the fun part, to create the nuget package. I run a simple batch script like this:

NuGet.exe pack filament.nuspec -OutputDirectory builds\nuget\x86_64

Thereupon I can look in my builds\nuget\x86_64 directory and see a nuget package named Google.Filament.2019.8.8.nupkg

Call Nuget Push

Now that the package is created, it’s time to push it up to a nuget feed. Which nuget feed you push up to is up to you, and is none of my business. But nuget.org is the defacto source. But if you have a private feed you use for your company that works too. I run a simple batch script like this:

NuGet.exe push builds\nuget\x86_64\*.nupkg -Source https://<some nuget url> -Apikey <some api key>

Create a packages.config file

This part is super easy. Create a packages.config file in the same directory as the visual studio project file (*.vcxproj) that will be consuming the nuget package.

Place the following xml snippet into the file:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Google.Filament" version="2019.8.8" />
</packages>

Notice how the version matches what was put inside the *.nuspec file.

Edit the visual studio project file

This step involves a text editor (I prefer Notepad++ or Visual Studio Code). This step is also markedly different from what we would use if we were using visual studio to find a managed .net nuget package for a managed .net project.

But since this is a native project, we don’t get the big boy tools, and have to settle for the hand-me-downs from Microsoft.

First we will open the *.vcxproj file that will be consuming this project, and will simply add the following line of xml code at the end of the file:

<Import Project="<Your package directory>\Google.Filament.2019.8.8\native\filament.props" />

Where your packages go, is up to you when you do a nuget restore. So where-ever that is, you will have to change the snippet <Your package directory> to point to where-ever it was that nuget unpacked the files. This can be a relative or an absolute path, so it’s up to you. But in the end, msbuild needs to be able to find that *.props file, otherwise it won’t load in visual studio.

Summary

And that is it. The package is done, and you should be able to do a nuget restore and build your native project. Many of the steps were the same as creating a managed .NET nuget package. With the exception of the manual editing of the native project files.

If you are looking for more examples of nuget packages holding native projects, do a search on nuget.org, and find a project. Browse to the page for the nuget package and find the link to the ‘project’ code page for it. Usually on github.com. Click on the link to open the project in Github and then hunt around for a *.nuspec file.

Pointer Truncation

Pointer truncation is an evil that all developers of native C++ code need to worry about. This is simply storing a wide piece of memory in a narrower bit of memory. This can become an issue on applications that are ported from 32 bit to 64 bit. In 32 bit applications, pointers are of course 32 bits wide. So it is no big deal to do something like this:

int* foo = new int[45];
int bad = (int)foo;

However in 64 bit applications, that is bad. Since that pointer could be using the high bits of it’s memory address, and when cast or truncated to a 32 bit int, it will lose information. The high bits of a pointer are the bits that pointer to regions higher than 0xFFFFFFFF. For instance a 32 bit pointer has 8 digits (in hexadecimal notation) and can look like this:

0x12345678

But a 64 bit pointer has 16 digits (in hex) and can look like this:

0x1111111122222222

The bits above that are 1 are the high bits. Since a 64 bit app can address more than 2^32 bits of memory, these bits can get used if the 64 bit app requires lots of memory. There is a way to force pointers to be assigned to the higher regions of memory without the expense of allocating all that memory. That way is to use VirtualAlloc in the Windows API, and reserve (but not commit) the lower 4 Gigs of memory. 

The results of a random debugging session involving the code below, shows that the high bits are completely lost when stored in the variable bad.

// a pointer, which is 64 bits wide on a 64 bit platform
int* foo = new int[45];
// this will truncate the memory pointer
int bad = (int)foo; // PURE Evil! Integers are 32 bits wide

Notice how the integer loses the leading value from the pointer (circled) as shown in the debugger watch window below: image

If the coder really gets adventurous they can try converting that integer back to a pointer again, with especially disastrous results:

// a pointer, which is 64 bits wide on a 64 bit platform
int* foo = new int[45];
// this will truncate the memory pointer
int bad = (int)foo; // PURE Evil! Integers are 32 bits wide

// an accident waiting to happen
int* worse = (int*)bad; // catastrophic!
// worse now looks like this: 0xffffffffa0040140
// now the high bits of 'worse' are filled with 0xff, which automatically
// makes it point to invalid regions of memory
// Any accessing of this pointer will result in an access violation.

which shows this in the debug watch window:

image

Notice how the high bits of the pointer worse are now pointing to regions of memory that the windows kernal has flagged as off limits. Any attempt to do anything with this pointer will result in an access violation, and if not correctly handled will result in the termination of the application.

One good way to find these is to call VirtualAlloc with very big values when your application begins. (I’m simplifying greatly here, trust me). This will reserve large chunks of memory below 4 Gigs. So that by the time your application makes actual memory allocations, all or most of the pointers will be above the 4 Gigs boundary mark. Then you have to test your application quite thoroughly to flush out these hot spots.

Well you might ask, should not the compiler aid you in this situation? Not the MS VC++ 10.0 compiler. Even at warning level 4, nothing is emitted to warn about the truncation.

Also Code Analysis will not help as it not enabled on 64 bit builds. i.e.

1>—— Build started: Project: VirtualMemTest, Configuration: Debug x64 ——
1>cl : Command line warning D9040: ignoring option ‘/analyze’; Code Analysis warnings are not available in this edition of the compiler

And on 32 bit builds of the same code code analysis still emits no warning.