Leider ist der Eintrag nur auf Amerikanisches Englisch verfügbar. Der Inhalt wird unten in einer verfügbaren Sprache angezeigt. Klicken Sie auf den Link, um die aktuelle Sprache zu ändern.

This article discusses a way how to create and use a NuGet Package for Libraries which are not yet stable and which are still under active development.

Especially, the core idea is to develop such an library and a project consuming this library in an efficient way.

Concept

As we develop on Windows with Visual Studio, NuGet is a powerful tool to manage library dependencies in Projects, for external 3rd Party libraries, as well as for our own libraries. Using Git our alternatives would be:

  • Git Submodules – with their known problems (detached head, multiple commits, etc.)
  • cmake – vs. Visual Studio solutions
  • manual paths / zip packages – manual work

Using NuGet seems the way to go for Windows-Only projects. Even for native c++ components. (Side note: coapp is dead and is not missed.)

The Problem

However: if we have a library component and a consuming project, which we have to actively develop both at the same time, the NuGet process gets prohibitively tiring. For each change in the library, we need to build the lib, repack the NuGet package, increasing its (build) version number, update the consuming project’s NuGet reference, and build the project… For every tiny typo.

The Idea

The core idea is to prepare the NuGet package in such a way, that a local override of the package’s content is possible. Think of an environment variable holding the file system path to the library’s development directory. If this environment variable is not set, the content of the NuGet package is use. If the environment variable is set, then include paths and library paths are set to directly use the files found in that development directory (obviously, resulting in an unclean in-development version of the project).

Since native NuGet packages simply use an MSBuild script to integrate themselves into a project, we have (almost) all the possibilities MSBuild has to offer.

Set up the NuGet Package

Creating a native C++ library NuGet package without coapp is not very difficult, but out-of-focus of this article. For the sake of simplicity I only discuss the (second) easiest task: a static library. We need some header file and some static library files. All in all the whole file looks like this:

NugetDevPackageTest.testLib.nuspec

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <!--
    Create package:
    cd solution directory
    nuget pack NugetDevPackageTest.testLib.nuspec -Version 0.2.0-build001
    -->

  <!-- package metadata -->
  <metadata>
    <id>NugetDevPackageTest.testLib</id>
    <version>$version$</version>
    <title>NugetDevPackageTest testLib</title>
    <authors>Sebastian Grottel</authors>
    <projectUrl>https://bitbucket.org/sgr_faro/nuget-dev-package-test/overview</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Nuget package of `someLib` to test dev nuget package concept</description>
    <tags>nugetdevpackagetest testLib native</tags>
  </metadata>

  <!-- content -->
  <files>
    <!-- include header files -->
    <file src="DemoClass.h" target="build\native\include" />

    <!-- static libraries -->
    <file src="lib\Win32\Debug\some.lib" target="build\native\lib\Win32\Debug" />
    <file src="lib\Win32\Release\some.lib" target="build\native\lib\Win32\Release" />
    <file src="lib\x64\Debug\some.lib" target="build\native\lib\x64\Debug" />
    <file src="lib\x64\Release\some.lib" target="build\native\lib\x64\Release" />

    <!-- build rules -->
    <file src="NugetDevPackageTest.testLib.targets" target="build\native" />

  </files>
</package>

There are two interesting aspects to highlight here:

  1. The static libraries can be collected from any directories. Important is that you specify the correct target directories. Follow the semantic rules NuGet specifies.
  2. The first build rule file, NugetDevPackageTest.testLib.targets, controls the integration of the NuGet Package’s content into the Visual Studio project. This file must have the same name as the package itself.

We set up the targets file as follows:

NugetDevPackageTest.testLib.targets

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- If development directory is empty, use content from the package -->
  <PropertyGroup Condition="'$(NugetDevPackageTest_testLib_DevDir)' == ''">
    <__NugetDevPackageTest_testLib_IncludeDir>$(MSBuildThisFileDirectory)include/</__NugetDevPackageTest_testLib_IncludeDir>
    <__NugetDevPackageTest_testLib_LibrarayPath>$(MSBuildThisFileDirectory)lib\$(Platform)\$(Configuration)\some.lib</__NugetDevPackageTest_testLib_LibrarayPath>
  </PropertyGroup>

  <!-- If development directory is set, use the content found there -->
  <PropertyGroup Condition="'$(NugetDevPackageTest_testLib_DevDir)' != ''">
    <__NugetDevPackageTest_testLib_IncludeDir>$(NugetDevPackageTest_testLib_DevDir)/</__NugetDevPackageTest_testLib_IncludeDir>
    <__NugetDevPackageTest_testLib_LibrarayPath>$(NugetDevPackageTest_testLib_DevDir)\lib\$(Platform)\$(Configuration)\some.lib</__NugetDevPackageTest_testLib_LibrarayPath>
  </PropertyGroup>

  <!-- If development directory is set, define an additional macro -->
  <ItemDefinitionGroup Condition="'$(NugetDevPackageTest_testLib_DevDir)' != ''">
    <ClCompile>
      <PreprocessorDefinitions>HAS_NUGETDEVPACKAGETEST_TESTLIB_DEVDIR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>

  <!-- Compiler options: package macro and include paths -->
  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions>HAS_NUGETDEVPACKAGETEST_TESTLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(__NugetDevPackageTest_testLib_IncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <ResourceCompile>
      <AdditionalIncludeDirectories>$(__NugetDevPackageTest_testLib_IncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ResourceCompile>
  </ItemDefinitionGroup>

  <!-- Linker options: library (full) path -->
  <ItemDefinitionGroup>
    <Link>
      <AdditionalDependencies>$(__NugetDevPackageTest_testLib_LibrarayPath);%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>

</Project>

Create the NuGet package:

nuget pack NugetDevPackageTest.testLib.nuspec -Version 0.2.0-build002

(obviously, you adjust the version number as you like to.) and be happy that it already does work as you intended: if the environment variable NugetDevPackageTest_testLib_DevDir is set, the content of this folder is used instead of the NuGet package’s content.

Setting an environment variable and the need to restart Visual Studio any time you change it, this is obviously not great. We can improve on that by adding a GUI.

Visual Studio Property Page

We add an Visual Studio property page for your project to the NuGet package, allowing us to change the setting of the variable from within Visual Studio. For this we add an XML description of the values we want to change:

overrideSettings.xml

<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework">

  <!-- Project property settings to override content of nuget development packages -->
  <Rule Name="ProjectSettings_NugetDevOverride" PageTemplate="tool" DisplayName="Nuget Development Override" SwitchPrefix="/" Order="1">

    <!-- Category to identify this package -->
    <Rule.Categories>
      <Category Name="NugetDevPackageTest_testLib" DisplayName="NugetDevPackageTest.testLib" />
    </Rule.Categories>

    <!-- Store override settings only in the user file -->
    <Rule.DataSource>
      <DataSource Persistence="UserFile" ItemType="" />
    </Rule.DataSource>

    <!-- Override development path -->
    <StringProperty Name="NugetDevPackageTest_testLib_DevDir"
      DisplayName="Development Directory"
      Subtype="folder"
      Description="Override content of Nuget package with content of this directory. If this field is empty (default) the content of the nuget package is used. This value is persistent as user setting only."
      Category="NugetDevPackageTest_testLib" />

  </Rule>
</ProjectSchemaDefinitions>

Note that the StringProperty directly stores it’s value in the variable we are already using. Make sure not to use this variable as an Environment variable anymore!

Now, we reference this property page from the other files of our NuGet package:

NugetDevPackageTest.testLib.nuspec

...
    <!-- build rules -->
    <file src="NugetDevPackageTest.testLib.targets" target="build\native" />
    <file src="overrideSettings.xml" target="build\native" />

  </files>
</package>

 

NugetDevPackageTest.testLib.targets

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- include the gui property page to override the development directory -->
  <ItemGroup>
    <PropertyPageSchema Include="$(MSBuildThisFileDirectory)\overrideSettings.xml" />
  </ItemGroup>

  <!-- If development directory is empty, use content from the package -->
...

Now create the new version of the package. Update the package reference in your consuming project. You might need to restart visual studio once. And you should find the new property page in the settings of your project.

Use the NuGet Package or the local Version

Be Aware of all the pitfalls

  • Never commit the .user file of your projects to the repository!
  • If your project code requires local changes within the code usually packed into NuGet, your project will not compile correctly on any other machine!
    • Before you push, or at least before you create a pull request, you need to push and publish the changed NuGet project and you need to reference the NuGet package cleanly without override.
  • You need to use two Visual Studios running, one for your project and one for the NuGet-ted project.
    • If you run your project in the debugger, and you step into functions from the NuGet project, the corresponding source file is opened in the Visual Studio of your project. You can edit the files there, but of course you cannot compile the NuGet library here. Remember to switch to the right Visual Studio for that.

The Proposed Process

testApp – Visual Studio #1 testLib – Visual Studio #2 Comment
Clone testApp
Open testAppsolution in Visual Studio #1
Build testApp This fetches the NuGet package of testLib and builds the App with the content of that package, e.g. version 1.0.0
Clone testLib
Open testLib solution in Visual Studio #2
Build testLib
(Build testApp) Nothing changes. Still the NuGet package is used. Build should not do anything (up to date)
Open Project settings and override the nuget settings. Reference the directory where you cloned and built testLib
(Build testApp) Known Issue: Visual Studio still believes the project would be up to date
Rebuild testApp App is now built with the testLib built in your local directory!
(Build testApp) The project is up to date (which is correct)
Change some code and build testLib
Build testApp The project correctly detects that it needs to build (at least to link) again. The changes of the local testLib can directly be used.
You start testApp in the Debugger You can even enter code of testLib, look at local / private variables, etc. The corresponding source files of testLib are opened in Visual Studio #1!
You edit source of testLib WRONG Visual Studio!
You hit Build → testApp is up to date It is the wrong Visual Studio. You cannot build testLib there. You need to switch to the other Visual Studio
Visual Studio might detect the changes at the source files, if they are opened. If the files are not opened, everything is ok. If Visual Studio does ask you, select to keep changes made outside Visual Studio #2
Hit F5 (start Debugging) Binary and source code do not match! Visual Studio #1 should warn you about it if you try, e.g., to set a breakpoint in source code of testLib
Build testLib The testLib is update with the changes to the source code you made in Visual Studio #1
Hit F5 (start Debugging) Visual Studio #1 correctly detects the updates of testLib, builds again, and executes testApp with the newest version of testLib.
 

 

 

Develop your changes in testApp and testLib. Now you are finished and want to push a stable version to your CI system

Be sure testLib is correct in all configurations
Commit + Push testLib
Trigger built / update of new NuGet package (we call it Ver++)
Disable the override settings for the NuGet package
Update the testApp project to use the NuGet package Ver++ Ideally this package should be the result of your CI system.
Compile and testApp in all configurations Since you had the identical code tested before locally, this should not show any problems. If it does, you likely missed something before.
Commit + Push your final update of testApp This should be solely the increment of the NuGet package version
Build / Test your testApp on your CI system All should work fine.

Known Issues

Visual Studio Property Pages GUI

The Visual Studio GUI is sometimes not correctly updated. One such situation is created by the property page descriptions injected via NuGet packages.

If you initially add a NuGet package with such a property page, or if the NuGet package you are using changed its property page, Visual Studio might not show you the right proptery page (or might not show any property page).

If this happens, restart Visual Studio after installing / restoring the NuGet package and you should be fine.

Visual Studio’s Fast Up to Date Check misses Changes of the StringProperty

When in Visual Studio a build is triggered (e.g. by pressing F5 for a Debug start), Visual Studio does not invoke MSBuild to determine if the project is up to date. Instead is uses an internal mechanism to quickly decide if a rebuild is required. This internal mechanism, known as fast up to date check, does not perform all required checks. E.g., it misses changed to the paths defined by the variable defined within the property page GUI created by our NuGet package.

This means, whenever the value of this variable is changed, you should trigger a rebuild of the consuming project.

One workaround would be to disable the fast up to date check for this project. However, for large projects, like SCENE, this introduces more pain than the required rebuild.

cf.: https://stackoverflow.com/q/47516374/552373

Version Schizophrenia

There is an semantic problem: you reference a Nuget package version, e.g. 1.0.0. But you override the content with changed files. Those will eventually be published as a new version, e.g. 1.0.1. But until then, your consuming project will reference those as version 1.0.0.

Your build process must be aware of this issue.

You should introduce integration tests to make sure such information mismatch never enters release branches.

Deep Dependency Graph Version Conflict

Consuming the unstable library from the development directory, is a project setting, not a solution setting. If you have a deep dependency graph and you are consuming this library via multiple routes, the override setting only influences one single route! Especially, if you use another Nuget package which uses your lib nuget, you cannot do anything about it. You need to be carefully aware of potential binary compatibility issues in such a construct.

Workarounds could be based compile-time and run-time checks of version numbers and the „dirty-lib-flag“ (cf. HAS_NUGETDEVPACKAGETEST_TESTLIB_DEVDIR).

Hi, Ich habe das NuGet-Paket für GLFW mal wieder aktualisiert.

Der Inhalt ist prinzipiell identisch geblieben, aber es gibt drei wichtige Änderungen:

  • Die Versionsnummer nutzt nun vier Zahlen: 3.2.1.5. Die vierte Zahl ist die Paket-Build-Nummer, welche ich erhöhen kann wenn ich ein Paket erneuern muss obwohl ich den Inhalt nicht ändere. Damit sollte ich endlich diese „Pre-Release“-Flags los werden, die ich bisher benutzt hatte, vor allem für die VS 2017 fixes.
  • Ich benutze CoApp nicht mehr. CoApp ist tot und wird nicht vermisst. In der Arbeit habe ich begonnen meine eigenen .nuspec- und .targets-Dateien direkt selbst zu schreiben. Und ich muss sagen, das ist weder besonders schwierig, noch besonders viel zu tun.
  • Und als letztes, I habe Properties dem Paket hinzugefügt, welche in Visual Studio als Property Page in der GUI verfügbar sind. Darüber können Projekte die das Paket nutzt nun eine Configuration und ein Toolset erzwingen. Das ist besonders hilfreich wenn man spezielle Configurations hat die nicht automatisch von NuGet erkannt werden. Nun kann man diese zumindest von Hand setzen.

Natürlich ist der aktuelle Stand auf bitbucket verfügbar.

Jetzt warte ich nur noch darauf, dass die nächste Version von GLFW veröffentlicht wird.

Leider ist der Eintrag nur auf Amerikanisches Englisch verfügbar. Der Inhalt wird unten in einer verfügbaren Sprache angezeigt. Klicken Sie auf den Link, um die aktuelle Sprache zu ändern.

And now there is Voro++ on Nuget. Voro++ is a library and utility, written by Chris Rycroft (with Applied Mathematics in Harvard SEAS) for compute Voronoi cells für 3D data. I use his lib actually to compute natural neighbors in my particle data sets. For me, Voro++ is better suited than other libs, like e.g. qhull, for several reasons: it is easy to use, streamlined for 3D, and natively support periodic boundary conditions. The single drawback I found, there are no official binary releases for Windows. And that is why I started this nuget package.

The library’s source code is rather clean and compiles without problem in Visual Studio. So all I did, was compiling the static library for the four latest Visual C++ versions, and I put the nuget package together. My Visual Studio solution and project files are also publicly available on bitbucket: https://bitbucket.org/sgrottel_nuget/voro

The package contains the static library, the header files, some files from the documentation, and the command line tool built with MSVC 2015. If you only want the command line tool and don’t care for the lib, simply download the nuget package, unzip it (yes, nuget packages are basically zip files), and you’ll find the exe in the tools subdirectory. For the full documentation of the library, go the Chris’ website or the original source code package.

What I didn’t include in the nuget package are any samples. But compiling them for yourself is as simple as it could be:

1. start a new C++ console application in visual studio.

Be sure to deactivate precompiled headers and to make the project empty.

voromsvc01

2. drag-drop-add any cc-example.

Just use any file from Chris’ source code package into the project.

voromsvc02

3. Add the voroplusplus nuget package.

voromsvc03

4. And you’re done! Compile it and run it by a push of a button.

Have fun!

Ich habe nochmal ein Nuget-Paket adoptiert: Lua

Der Grund dafür ist, natürlich, MegaMol, genauer eine geplante Erweiterung von MegaMol die Skript-Steuerung aller interner Verwaltungsfunktionen ermöglichen soll. Nach einigen Überlegungen haben wir uns für Lua als Skriptsprache in unserem Projekt entschieden. Lua selbst zu bauen ist einfach, aber ich wollte auch den Bauprozess des gesamten MegaMol möglichst simpel halten. Das schreit unter Windows nach einem Nuget-Paket.

Natürlich gab es das Paket schon, wenn auch veraltet. Anstatt ein neues Paket zu starten, habe ich die Autoren im coapp-Team angeschrieben. Die waren glücklich, dass ich aushelfen wollte und haben mir schnell und gerne Zugriff zu dem Paket gegeben, damit die Binaries erneuern konnte. Ich werde mein Bestes tun damit das Paket einigermaßen aktuell bleibt und möglichst viele Visual-Studio-Versionen und -Einstellungen unterstützt.

I präsentiere ein weiteres NuGet Paket: GLFW. Ok. Das Paket wurde ursprünglich mal von redxdev erzeugt. Alles was ich gemacht habe war, die offiziellen Binaries von www.glfw.org zu nehmen und neu zu verpacken. (Aber irgendwer muss das ja machen.) Und den ganzen Spaß habe ich nur gemacht, damit das Paket mit Visual Studio 2015 kompatibel wird.

NuGet ist ein praktisches Paket-System für Visual Studio. Ursprünglich für Dotnet-Bibliotheken gedacht, wurde es vor einiger Zeit erweitert um auch native C++-Projekte zu unterstützen. Das Problem an der ganzen Sache ist ganz einfach: die Paketen müssen aber noch geschnürt werden. Es gibt einige, jedoch bei weitern nicht alles was man (ich) so für die tägliche Arbeit braucht. Im Besondern sind die meisten Pakete auch noch nicht mit Visual Studio 2013 kompatible. Und Visual Studio 2015 ist ja schon in den Startlöchern.

Also gibt es nur eins was ich tun kann: mit machen! Ok, ich könnte auch einfach nur vor mich hin nörgeln, aber diese Option klammere ich mal aus. Also, hier ist es, mein erstes NuGet-Paket:

die AntTweakBar v1.16

(mit freundlicher Unterstützung des Autors)

Und dieses Paket wird nicht mein letztes bleiben.