Vor einiger Zeit haben zwei Kollegen etwas Zeit und Aufwand investiert um unsere Haupt-Code-Base und unsere Build-Chain auf Visual Studio 2017 und den C++17-Standard zu haben. Eine sinnvolle Aktion. Aber natürlich war das auch Grund genug, dass ein anderer Kollege und ich dann rumgewitzelt haben, dass wir unseren Code downgraden sollten, auf C++03, C++98, oder vielleicht sogar direkt auf C. Keine sorge, wir haben alle vier gut gelacht. Oder?

Zu der Zeit hat mich der Rumwitzel-Kollege auf einen Artikel von aras-p über „Modern C++ Lamentations“ aufmerksam gemacht. Lesen! Der ist gut. Und denkt nicht „das ist vielleicht in der Computerspieleindustrie so, trifft aber für mich nicht zu.“ Ich arbeite nicht in der Computerspieleindustrie, und auf meine Arbeit trifft das ganze Zeug ziemlich 100%ig zu.

Meiner Meinung nach ist  „modernes“ C++ zu komplex, zu aufgeblasen, zu angeberisch: „schaut her wie cool mein code ist“. Hier wird ganz das Ziel verfehlt, nämlich Probleme zu lösen.

[…] to me this feels like someone decided that “Perl is clearly too readable, but Brainfuck is too unreadable, let’s aim for somewhere in the middle”.

Viele neue Sprach-Features sind sinnvoll, andere sind vielleicht nur „cool“. Natürlich sieht das jeder anders und findet andere Aspekte sinnvoll. Es gibt aber Dinge die objektiv gesehen schlecht sind. Der Artikel von aras-p zeigt hier schön die Probleme von Compile Time und Debug Performance. Das sind berechtigte Gründe.

C++ compilation times have been a source of pain in every non-trivial-size codebase I’ve worked on. […] Yet it feels like the C++ community at large pretends that is not an issue, with each revision of the language putting even more stuff into header files, and even more stuff into templated code that has to live in header files.

In der Schule war ich Hobby-Programmierer; dann Student in Software Engineering und Teilzeit-Programmierer nebenher; dann habe ich meinen Doktortitel in Informatik gemacht, Schwerpunkt in Computergraphik und Visualisierung, und habe parallel eine großes modulare, high-performance Visualisierungssoftware geschrieben; dann war ich Senior Software Engineer in einer Firma mit einer recht großen Software; und jetzt bin ich Manager eines Teams von Software-Entwicklern. Ich denke ich kann sagen, ich hab die meiste Zeit meines Lebens programmiert. Ich mach immer noch Kleinigkeiten und kleine Bug fixes in unserem Code, selbst als Manager. Vermutlich denk sich mein Team, ich soll endlich die Finger von „ihrem Code“ lassen. Werde ich nicht. Aber, was ich sagen will:

Ich bin praktisch mein ganzes Leben schon Programmierer. Und dabei habe ich in weiter über einem Duzend verschiedener Sprachen gearbeitet (während dem Schreiben dieses Artikels kam ich auf 15, ohne Script-Sprachen. Aber wahrscheinlich hab ich auch welche vergessen.) Mit dieser Erfahrung nehme ich mir heraus zu sagen:

C++ ist nicht die beste Programmiersprache. Modernes C++ hat nicht alles besser gemacht.

Bitte! Fangt (wieder) an euch zu fragen „wie löse ich dieses Problem“, anstatt „wie löse ich dieses Problem mit variadic Templates in Lambdas mit Ranges, weil das alles so cool ist“.

Als ich an der Universität meine Vorlesung zu „C++ für Computergraphik“ gehalten habe, da konnte man die ganzen unterschiedlichen Typen der heranwachsenden Programmierer klar und deutlich sehen. Und das gibt es diese eine besondere Teilspezies der „Programmierkünstler“. Programmierer die ihren Code für Kunst halten, und über all diese gewöhnlichen Programme erhaben. Das werde ich jetzt erstmal nicht weiter kommentieren. Aber ich glaube festgestellt zu haben, dass diese Typen in Umgebungen wo C++ eingesetzt wird sehr häufig anzutreffen sind. Leider.

Als Abschlussbemerkung: Wenn ich heute ein neues Programmierprojekt starte, und ich darüber nach denke welche Programmiersprache(n) ich dafür einsetze, dann ist C++ nicht mehr oben auf der Liste.

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.

One of my old computer science professors, back in the days, used to say, if you use a debugger while you are writing your code, you are a bad programmer. My, oh my. What an idiot. It makes perfect sense to utilize a debugger as you proceed in completing your program. It’s a simple variant of divide and conquer. Let’s make sure one part does work, before we move on to the next. So, you see, I really value my debugger.

Many small tools I write are simple console applications. I do like graphical user interfaces a lot. And I prefer a graphical user interface over a command line interface any time. But for some small tools, especially ones which do not even require any interaction, setting up a graphical user interface is just too much work. So, even so it really is very old-school, console applications are often the right choice.

This brings us to developing console applications and utilizing the debugger. Visual Studio has a very nice feature for this scenario, when working with c++: it keeps the console window open and reuses it. At first this might seem useless. I know a lot of people which just close the window every time their application stops. But there is a clear and huge benefit from this function: since the console window stays open, you can inspect you application’s output for as long as you like without having to keep the debugger attached or starting your application in a separate console. This actually is really handy.

For csharp console applications, however, this feature does not exist. I really do not know why. And, I hope the Microsoft will deliver this feature soon for csharp applications as well. But for now, csharp has this horrible behavior that the console window closes as soon as the application exits. And this brings us back into the past, where we need some mechanism to keep the window open. One possibility is to utilize the debugger, which is attached anyway, to pause the application. I don’t want to do this using “normal” break points, as I use break points to do actual debugging. Meaning, I often delete all break points, and then only set those I need. Having to take care for some “special” break points would be a pain in the … well, you know.

Luckily, we can break the debugger by code. Whipping up some utility class, I got this here:

static class DebugHelper
{
  [Conditional("DEBUG"), MethodImpl(MethodImplOptions.AggressiveInlining), DebuggerHidden]
  static public void Break()
  {
    bool launch;
    var env = Environment.GetEnvironmentVariable("LAUNCH_DEBUGGER_IF_NOT_ATTACHED");
    if (!bool.TryParse(env, out launch))
      launch = false;
    if (launch || Debugger.IsAttached)
    {
      if (Debugger.IsAttached || Debugger.Launch())
        Debugger.Break();
    }
  }
}

Now, I can just call DebugHelper.Break(); anywhere I like.

They are removed in release builds. And the aggressive optimization removes the helper function from the stack, so that the debugger always breaks at the call of my helper function, and not within.

For now, this is handy. And, I really hope, that in the near future this will be obsolete.

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.

Previously, I wrote about using one global msbuild xml file to override nuget package content for local development. While this does work, it comes with a warning if multiple packages use this mechanism:

***Test\packages\***.0.7.1-prerelease-\build\native\***.targets(7,5):
warning MSB4011: "***Test\packagesoverride.xml.user" cannot be imported again. It was already imported at "***Test\packages\***.0.7.1-prerelease-\build\native\***.targets (6,3)".
This is most likely a build authoring error. This subsequent import will be ignored. [***Test\***Test.vcxproj]

While this is not realy a problem, it is a warning. And I don’t like warning. I like my projects to build entirly without warnings.

A soltion for this comes from classic c++ programming: use an include guard. These are the changes required:

The packagesoverride.xml.user must define a default variable. I named it HAS_packagesoverride:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <HAS_packagesoverride>True</HAS_packagesoverride>
    <NugetDevPackageTest_testLib_DevDir>C:\Dev\SomeProject\Dir</NugetDevPackageTest_testLib_DevDir>
  </PropertyGroup>
</Project>

And now importing this xml in the nuget packages‘ target files can this for this variable to avoid multiple import:

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

  <!-- Import override settings, if they exist -->
  <ImportGroup>
    <Import
      Condition="Exists('$(SolutionDir)packagesoverride.xml.user') and '$(HAS_packagesoverride)' != 'True'"
      Project="$(SolutionDir)packagesoverride.xml.user" />
  </ImportGroup>

<!-- ... -->

 

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.

Previously, I wrote about using NuGet for software components, which are still in active development. One of the most important factors was the capability to override the nuget package’s content with content fetched from a directory, e.g., a working copy clone. The key element for this was a MSBuild variable NugetDevPackageTest_testLib_DevDir.

The original plan was to edit this variable using a project property page. While having a UI is nice, this has proven not to work on larger projects. The reason is simple: in larger projects, we talk about a vs solution with multiple vc projects, and many of these projects might reference our NuGet package. If we now need to switch to our local directory, we need to adjust the project properties for every project consuming the package. This is tiring and error prone. Forget to adjust just one project and you might end up with inconsistent builds. Therefore, I was seeking a more centralized configuration.

Update 2019-03-02

I updated the code examples to reflect the updates I recently came up with.

Dev. Override – II

The principle idea of having a variable to control the override remains valid. The targets in your nuget might look like this:

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

  <!-- ... -->

  <!-- Compiler settings: defines and includes -->
  <ItemDefinitionGroup Condition="'$(NugetDevPackageTest_testLib_DevDir)' == ''">
    <ClCompile>
      <PreprocessorDefinitions>HAS_NUGETDEVPACKAGETEST_TESTLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(NugetDevPackageTest_testLib_DevDir)' != ''">
    <ClCompile>
      <PreprocessorDefinitions>HAS_NUGETDEVPACKAGETEST_TESTLIB;HAS_NUGETDEVPACKAGETEST_TESTLIB_DEVDIR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories>$(NugetDevPackageTest_testLib_DevDir)\Project\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
  </ItemDefinitionGroup>

  <!-- ... -->

</Project>

The obvious question is the definition of our DevDir variable.

For this is propose a central msbuild xml at the level of the vs solution!

We include it in our targets file, right after the root Project tag starts:

<ImportGroup>
  <Import Project="$(SolutionDir)packagesoverride.xml.user" Condition="Exists('$(SolutionDir)packagesoverride.xml.user') and '$(HAS_packagesoverride)' != 'True'" />
</ImportGroup>

This line imports the msbuild xml file, if it exists. Notice, how the file name is generic and not related to our specific package. This is because multiple nuget packages can share this file!

The content of this central configuration is very simple:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <HAS_packagesoverride>True</HAS_packagesoverride>
    <NugetDevPackageTest_testLib_DevDir>C:\Dev\SomeProject\Dir</NugetDevPackageTest_testLib_DevDir>
  </PropertyGroup>
</Project>

Now if you need to override a nuget package for your whole solution, just create this file!

Drawback 1: If the file did not exist previously, an you create it, then you need to rebuild all projects with nugets referencing this package. Because they might be affected by this file.

However, once the file does exist, changes to the file are currectly and automatically detected by visual studio, and build operations are correctly triggered in the affected projects. So, it might be a nice idea to keep a file with an empty property group in place, just in case.

If you need to override multiple nugets at once, just add multiple entries into this one property group.

Drawback 2: There is no UI. So you need to edit it in your favorite text editor, meaning, you are prone to all typing errors you can come up with.

All in all, I believe this central file for the nuget override configuration is an improvement.

Ich bin ein visueller Kerl. Das heißt, ich mag alle möglichen Arten von visuellen Repräsentationen abstrakter Daten. Natürlich mag ich also auch die ganzen fetzigen Badges die überall im Internet rumfahren. Es macht also nur Sinn dass ich die auch selber nutze.

Shields.io stellt Badges für Source-Code-Zeug zur verfügung. Und so, ohne Umschweife, hier ist die visuelle Zusammenfassung aller Nuget-Pakete die ich betreue:

Es ist Zeit einen meiner Lieblingsstrips von xkcd zu rebloggen: tar

I don’t know what’s worse–the fact that after 15 years of using tar I still can’t keep the flags straight, or that after 15 years of technological advancement I’m still mucking with tar flags that were 15 years old when I started.

Es gibt viele solche Tools die noch heute benutzt werden, obwohl sie von Anfang an Müll waren. Jaja, das Beispiel hier macht sich über Nix lustig. Es gibt aber auch viele ähnliche Beispiele aus dem MS-Windows-Ökosystem.

Ich mach mich gar nicht über diese Tools lustig. Ich mach mich über die Leute lustig die noch heute diese Tools befürworten!

Ich habe meinen alten Webhoster hinter mir gelassen und meine Webseite umgezogen.

Das war jetzt dringend nötig.

Ich hab auch das WordPress aktualisiert. Nun scheint das Plugin für mehrsprachige Posts nicht mehr richtig mit dem Editor zu funktionieren. Naja. Das ist ein Problem für ein anderes Mal.

Meine Spielidee „SpringerJagd“ werde ich nicht weiter verfolgen.

Das Projekt ist schlicht der notwendigen Priorisierung meiner ganzen Projekte zum Opfer gefallen. Schade, aber es ist besser so. So habe ich mehr Zeit gezielt für andere Projekte. Und von denen werde ich schon bald hier schreiben. Und mit „bald“ meine ich in ein paar Monaten, oder so.

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.

HtmlAgilityPackAs can be read on the internet: HtmlAgilityPack is not for beautiful, aka human readable, html files.

“[…] it’s a ‘by design’ choice.” [https://stackoverflow.com/a/5969074]

So everyone redirects you to some other library.

Now, I am a bit stubborn. I want to use HtmlAgilityPack and I want to have indented, human-readable html files. The magic is within text nodes in the DOM. So, I wrote two utility functions to help me out.

First, to get rid of all unwanted whitespaces. This one might be a bit aggressiv, but it was ok for me:

static private void removeWhitespace(HtmlNode node) {
  foreach (HtmlNode n in node.ChildNodes.ToArray()) {
    if (n.NodeType == HtmlNodeType.Text) {
      if (string.IsNullOrWhiteSpace(n.InnerHtml)) {
        node.RemoveChild(n);
      }
    } else removeWhitespace(n);
  }
}

And, second, to create white spaces for line breaks and indentions:

internal static void beautify(HtmlDocument doc) {
  foreach (var topNode in doc.DocumentNode.ChildNodes.ToArray()) {
    switch (topNode.NodeType) {
      case HtmlNodeType.Comment: {
          HtmlCommentNode cn = (HtmlCommentNode)topNode;
          if (string.IsNullOrEmpty(cn.Comment)) continue;
          if (!cn.Comment.EndsWith("\n")) cn.Comment += "\n";
        } break;
      case HtmlNodeType.Element: {
          beautify(topNode, 0);
          topNode.AppendChild(doc.CreateTextNode("\n"));
          //doc.DocumentNode.InsertAfter(doc.CreateTextNode("\n"), topNode);
        } break;
      case HtmlNodeType.Text:
        break;
      default:
        break;
    }
  }
}

private static bool beautify(HtmlNode node, int level) {
  if (!node.HasChildNodes) return false;

  var children = node.ChildNodes.ToArray();
  bool onlyText = true;
  foreach (var c in children) {
    if (c.NodeType != HtmlNodeType.Text) onlyText = false;
  }
  if (onlyText) return false;

  string nli = "\n" + new string('\t', level);

  foreach (var c in children) {
    node.InsertBefore(node.OwnerDocument.CreateTextNode(nli), c);
    if (c.NodeType == HtmlNodeType.Element) {
      if (c.HasChildNodes) {
        if (beautify(c, level + 1)) {
          c.AppendChild(c.OwnerDocument.CreateTextNode(nli));
        }
      }
    }
  }
  return true;
}

As you might see, the code is pretty hacky. But, it works for me. Maybe, it also works for you, or it can be a starting point.

Und hier ist nochmal ein neues Nuget Package:

https://bitbucket.org/sgrottel_nuget/teamcity-gtest-streamer

https://www.nuget.org/packages/teamcity-gtest-streamer

Eine kleine Bibliothek für eine bessere Integration von GoogleTest in TeamCity. Tatsächlich ist es eine einzelne Datei als Header Only Library. Es gibt trotzdem ein Nuget-Paket für einfache Integration und Updates.