Why is Microsoft’s C++ support so messy?

Microsoft has probably the best IDE in the world. It’s called Visual Studio, and lately it has been messed up with unnecessary ALL CAPS menu entries and the ugliest colors possible, not to mention that awful flat look. Besides that, Visual Studio is still the best IDE around.

For C#. It’s almost inconceivable to think about .NET development without the great support of Visual C#. It is possible, but it shouldn’t be done.

For C++ it’s another story. Microsoft has a long history with C++; in about 20 years you’d think they had the time to polish the C++ integration. They didn’t. I shall explain using two issues.

The runtime issues

Writing a program in C++, you can no longer just deliver your executable file. You also have to deliver the runtime you built against. And make no mistake, if you built with VS2008 or you build VS2008 SP1 it makes a huge difference, you have to deliver different runtime versions.

It’s not very easy to identify which runtime version you have to deliver. But the worst thing is: you don’t really understand why. Why are there so many runtime versions? Why aren’t they delivered with the operating system? What the heck do they deliver in 3GB and in the ton of service packs?

On my machine I have currently 10 runtime versions.

Runtime versions

Runtime versions

From these 10, two are for VC++ 2005, 4 are for for 2008 (with two more with a different architecture) and two different are for 2010 for different architectures. This happened probably because I have 10 different applications written in C++ installed. This is not ok.

<story real=”true”>So if you write a TicTacToe and you want to send it to your relatives to see your first TicTacToe and play it, you’ll have to ask them to install the proper runtime version. Which you don’t really know which it is; and you’ll end up asking them to install the same Visual Studio version as you.</story>

The handling of DLLs in general

It’s not just the runtime. It’s the whole DLL handling that is a problem here. With C#, you just add a DLL to the references and voila, it works. C++ is different; you need a DLL, which contains the code, and you need header files (which are equivalent to the metadata from the DLL). The problem is more complicated when it comes to C++:

  1. In DLL exported functions and classes and variables are identified by their name. For C++ we need name mangling, in which the name of the function also will contain the class name, as well as the parameter types or an encryption of the parameter types. There is no standard way of doing this.
  2. Standard Template Library is not as standard as you’d think and cannot be delivered as binary code. For the time being, no compiler was able to create a way to deliver C++ template code in an efficient manner. Moreover, the STL is delivered as header files and most of the functions will be inlined. It’s part of why the STL is so efficient. But that means that you can’t refer these types in the exported functions, because the headers might be different from version to version. The size of a string might be different from the size of the string you returned from your DLL.
  3. Different compilation options might give you different data structures, with different sizes, different packing and different alignment in memory. This is not an issue to be taken lightly.

Most of the library implementers expose a C-compatible interface. C is simpler; all symbols names are exactly the function names, there are no classes and no complex types. They return a pointer, because a pointer has a fixed size, and parameters are passed as pointers as well, because it’s simpler that way. But C++ library implementation is a game of avoiding all these issues.

And Microsoft chose to make it more complicated. In order to link against a DLL, you have to link against a static library, delivered as a .lib file. You’ll have to copy the DLL manually in the debug folder, because you don’t really want to install the DLL in the Windows folder. And you don’t want to install the DLL in the Windows folder because God knows how many other applications will require that DLL, and you’ll mess up those application with your version. This is how DLL hell was born, but this didn’t change. At all.

Is it possible to have this changed? On Linux things are a lot easier. There was only one name mangling scheme change, between GCC 2.9x and GCC 3.x, that made shared objects incompatible. This change is big enough, and was not seen in the Microsoft universe (where things stay ABI compatible for a long long time). To support this, you only had to have two shared objects, one for 2.9x and one for 3.x. The linking was done against, say libstdc++.so.2 which was a symlink to the proper implementation of the 2.9x ABI. Applications that used the new ABI just linked against libstdc++.so.3, symlink to the current 3.x ABI, which makes sense.

Moreover, to develop you only need the header files in addition to the shared object. No static library that you also need.

Things are a lot simpler on UNIX-like systems. And Microsoft hasn’t made much to alleviate these issues. If you don’t believe me try writing a program in C++ using SDL, with Microsoft’s Visual Studio Desktop Express Edition.

So, although Microsoft has done some things to improve C++ support in VS2012, it’s still far from being a friendly developer environment. I never felt as comfortable with C++ as in Linux distributions, and probably never will, by the way things are going.

And most of Microsoft Windows IS C++. Strange.

Comments

Why is Microsoft’s C++ support so messy? — 11 Comments

  1. A. For your own apps always link statically. You can choose to link against the dll runtime, and non-dll runtime (static version). Of course, you have to specify that for every component of your app, both Debug and Release. Not a big deal though. It’s 2013 and most boxes have at least 4GB of RAM. DLLs are overrated.

    It works for boost too, btw, though you might have to rebuild it with the new linking type.

    Of course, don’t make your own DLLs unless you really have to.

    B. It’s not that great under linux either.

    Right now if you build with -std=c++11 and without -std=c++11, the code is not ABI-compatible. Not a problem if your visible functions are extern C, but that’s annoying and limiting.

    Let me tell you happened to me – I installed a free c++ library (pion-net), via debian apt-get. Came with .so, .a, .h files. All good. But my sample code was crashing in bizarre ways. After about 8h I realized that I was building my code with -std=c++11, but pion-net was not built that way. And the linker never complained once, of course.

    • A) They are rather good when you are the one that gives the software away; but indeed, they are overrated.
      Of course it works with boost, especially since boost will be included as headers in your project.
      DLLs are still priceless for two reasons: security (although a local attacker with elevated privileges will mess this up) and plugins. But indeed, I start to think they are more mess than worth.
      B) That’s insanity. I wonder what happened there. Does it do one of the huge mistakes of exporting functionality that has to do with STL? Like returning or receiving strings as parameters, and other stuff like that? I see no other obvious reason for this happening.

    • A) Sure, if your deliverable is a dll, then it’s gotta be a dll. And plugins make a lot of sense too.

      Don’t quite see the security angle though. The benefit of replacing a dll (potentially by the user) if there’s a security bug is minor, IMO.

      B) The insanity is in C++ :). I don’t really see the point of having C++ libraries if you’re restricted to a C interface. Indeed, the library in question passed strings around (and collections of strings too – that’s where the problem was coming from).

    • A) The security angle being that the libraries you rely on can be updated and their bugs fixed. It’s not uncommon to have bugs in glibc.
      B) Yes, that was to be expected in this case. But yeah, there is insanity 🙂 It rarely makes sense to have C++ libraries. being the messed up language that we know (and love). Unless, of course, you go the Qt way, where you implement a full framework.

  2. The all caps menus can be fixed by adding one registry key. It’s not that bad 🙂

    Regarding runtime issues, you could have always distributed the CRT dlls with your application.
    You were required to have a manifest file for Visual C++ 2005/2008. They’ve fixed this requirement with Visual C++ 2010 – no more need for a manifest file.

    Simply compile all your code / dependencies with the same compiler and everything just fine! 🙂

    • I agree with the last sentence, except for the “simply” part :). Ok, to be entirely correct, you need to compile with the same compiler and the same flags, too.

    • Agreed on the ‘except for the simply part’. It should not be necessary to have the same compiler, but you have to have an ABI compatible compiler and use the same flags. On Windows, although compilers are generally ABI compatible, this isn’t the case 🙁 So Microsoft actually made it harder lately to use their tools.

  3. Would you care to have a brief phone conversation with me about the issues you mentioned in this post?

  4. Pingback: The day I gave up on C++ | dorinlazăr.ro

  5. Pingback: QtCreator and the Visual C++ 2013 compiler | dorinlazar.ro