I work a lot with the Mako SDK, creating various samples and technology demonstrators. It’s great fun to get to play with the SDK so regularly, but the only snag is all the boilerplate setup that come with using a native C++ libraries and DLLs.
More or less, each time I start a new project, I have to:
- Add the header paths to project
- Link the libraries to project
- Add build steps to copies DLLs to output directory
- Make sure the right paths are used for each configuration/target
…and this is error prone and takes ages!
This led me to wonder what sort of support NuGet has for native C++ projects. Could I create a NuGet package to do this for me? Doing a little research, it seems that there were a lot of announcements in 2013 when it first came out, a small stub document and a blog post from the Visual C++ team which gave me some hints, but no really good ‘hello world’ examples. It also teases that there’s a part two, but for the life of me, I couldn’t find it!
It’s probably worth mentioning that the 2013 announcement about C++ support for NuGet mentions CoApp as a tool that can help generate NuGet packages for C++ projects. It looks good, but somewhat overkill perhaps for our library. Also, it looks like it’s no longer being maintained, so lets try and roll our own!
Understanding Native NuGet Packages
Creating a native NuGet package starts with the .nuspec file. This contains the metadata of the package (id, version, description, etc.). It’s pretty easy to create one of these up, and ours looks like this:
But on its own, this won’t really do much. It doesn’t know where the libraries are that we want to package.
To make things simple, we have our .nuspec file and Mako SDK libraries under the following structure:
To reference the libraries, we use a recursive wildcard to package everything under the build folder.
This snippet sits just under the Metadata tag in the .nuspec file.
You may notice that there is also a .props file. This is mentioned in the MSDN documentation, although not very well explained.
A package may also include targets and props files in \build that NuGet will automatically import into projects that consume the package. Those files must be named the same as the package ID with the .targets and/or .props extensions.
What this means is that the .props file could be thought of as an extension to the target .vcxproj project file. In other words, the .props file will contain all of the project configuration you’d usually manually put into the project to reference and link the new library you want to use.
When your NuGet package is installed, the target .vcxproj is updated with a link to the .props file, installed when your NuGet package is installed. When our Mako SDK NuGet package is installed, you will find that NuGet has added the following line to the target .vcxproj file:
This import means that the project will now use your .props file as it’s defaults. These can be overridden in the usual way.
So what do we put into the .props file for all the referencing and linking? I found the best way was to make the changes to reference the headers and link the libraries through the Visual Studio UI in a temporary project. I’d then view the .vcxproj file in a notepad and see the changes that Visual Studio made to the project file. From here, I copied them over to the .props file, changing as appropriate. Pretty simple!
That resulted in the following .props file
Thankfully Microsoft project files are fairly easy to read, but lets have a look at a couple of areas of interest.
The first section adds the header file path.
This makes use of the macro $(MSBuildThisFileDirectory). Although this doesn’t seem to appear as a macro option in Visual Studio 2017, it is indeed valid. This points to location of the .props file. So from here, we simply navigate on to the interface folder. We add the other default include directories by adding $(AdditionalIncludeDirectories) at the end.
The next section does three separate actions.
The first thing you’ll notice is that we have a condition set. This means the settings within, are specific to that configuration and target.
Next we set the project to use the static VC runtime.
We do this so that the target project compile settings match those used to create the libraries in the package.
The next section then adds both the library directory and the libraries to link.
In this case, we’re picking up the libraries for debug and x64.
Finally, since we have one DLL that’s used by our libs, we add a post build event to ensure it’s copied to the output directory.
And that’s very much it.
Building the Package
Once we’ve got everything in place we just need to compile it all into a NuGet package (.nupkg). This couldn’t be simpler, it’s a matter of downloading the latest NuGet command line executable and running the pack command:
Nuget.exe pack <path to .nuspec>
And so long as your relative paths are correct, and shiny new NuGet package will be your reward.
If you want to try it out straightaway, you add can a local source to visual studio. This will be the folder that the NuGet package is in.
Once installed, the props file should be linked to the target project and all references should be resolved. You’re free to use the Mako SDK in it’s entirety! Great!
An Alternative to NuGet?
It would perhaps be remiss of me to leave out the new packaging format which is gaining traction. It’s been built from scratch to better suit some of the complexities of native C++ projects. It’s called vcpkg and it’s currently being built as Open Source on GitHub.
The problems I have with using this at the moment are
- It’s currently in preview, with limited support
- It’s geared towards open source projects (ship the source, not the binaries)
- There’s not much documentation around creating packages (just consuming)
That said, it looks good, and it’s something that we’ll follow, to see how it goes.