Runtime compatibility for library packaging - c++

I want to package a library as a NuGet native package. This question is not specific to a way in which the packaged lib/dll/pdb/includes are distributed; but to be specific, I am looking at CoApp scripts (I wish there was something better I could link to), and I got an impression that there are too many different build targets, obtained combinatorially. I am trying to come up with a more or less minimal set of targets that is usable by applications that depend on the package. There are the following mostly orthogonal axes for build targets:
32 bit vs 64 bit. Obviously, this is legit.
Dynamic vs static builds. This is also sensible.
Debug vs. Release build. This also makes perfect sense, as debug builds reference the debug runtime (libcmtd.lib or msvcdrtd.lib) and the release builds reference the static runtime (libcmtd.lib or msvcdrtd.lib). Makes sense to include these to avoid a default library conflict.
The above are unquestionably good axes. The next one is questionable, although present in many examples:
_cdecl vs _stdcall vs __fastcall vs __thiscall. I think this makes little sense. The calling conventions would be supported for this particular library regardless of other linked libraries. Besides, variable arguments are for _cdecl only in Win32, and also 64 bit calling conventions are different anyway. My understanding is that anything I select will do, as long as header files declare a calling conventions compatible with the platform. Microsoft runtime libraries are not supplied for different calling conventions in any case.
And the next one I am not sure how to handle. Again, the examples declare
libraries build by different toolsets, which come with different Visual Studio versions: from v100 (v10.0, VS 2010) to vs140 (v14.0, VS 2015). My main question is, how compatible are the runtime libraries across different Visual C++ libraries? A problem here is we are using also other toolsets (Intel C++ is an example), and these usually have no corresponding packaging cases in CoApp, while being compatible with Microsoft runtimes.
I want to avoid packaging for a particular toolset. How possible is that, provided the code compiles with the oldest vesrion and also not using any newer runtime functions (e. g., v110 being the lowest supported version)? I am worried about two main things here (sorry, another numbered list starts here):
If I compile a static library with VS 2012 (provided bithood, staticity and debugness match), will I be able to link against it in VS2013 (its libcmt[d].lib)?
Under same conditions, will I be able to link against it in VS2010?
Same two questions, but speaking of a shared, DLL runtime?
Same questions, but taking into account runtime library defined exceptions that might be thrown by the library: will e. g. std exceptions be compatible up and down the version chain of the compilers, provided I compile the library with RTTI enabled?
More generally, is there a runtime compatibility matrix provided by Microsoft?
And if any other numbered list points, I'd like to hear that too.

Related

Can C++Builders clang32 compiler consume VS libraries

I'm trying out the clang32 compiler coming with C++ builder 10.2. Builder don't yet have any good support for CMake, so a great number of 3rd party libraries are (very) hard to compile using it.
Anyone knowing if there is any binary compatibility between clang32 and Visual Studio compiler?
There are essentially three different levels of compatibility you need to worry about:
File formats for object code and debug data, which allow you to use clang to build part of your project and Visual C++ cl.exe to build a library and then link them together and debug both.
Ability to write code and structure data that conforms to a portable binary interface, so it can be called across a mix of compilers.
Binary compatibility of the C++ standard library, so that standard library objects can be shared across a mix of compilers.
I can definitely say that (2) is supported and (3) absolutely is not; you can't even share standard library objects between different patchlevels of the same compiler. For (1) I don't know. A common way to bypass the issues with (1) is to build a DLL using each compiler, so they dynamically interface but no static linking nor merging of debug data is necessary.
If your concern is about cmake though, I think your problem is not the compiler (clang is available for Linux and cmake supports it well -- you should find the make scripts are capable of configuring all the compiler options). Whether it can generate project files for C++Builder is a different story, but perhaps you should consider using a different IDE. There are many with clang support, even Microsoft's Visual Studio has some ability to use clang for the compile step, and it's getting better with each release.

How can a C++ dynamic library with a C++ interface not break ABI between different compiler versions?

Recently I have been using the Assimp library for my hobby 3D graphics engine project in order to load 3D models.
The library comes in the form of a DLL accompanied by an import library (LIB) and an EXP file (only when building from latest sources; I understand it holds information about the exported functions, similar to the LIB)
Now, the surprise part, which made me ask this question, is the following:
I was able to correctly, without any build/link errors or run-time errors use the C++ interface of two different versions of the library:
The pre-built library, release 3.1.1, which was built and is dependent on an older runtime (MSVCP110.DLL, MSVCR110.DLL) (which I later decided to change to my own build since there was a linking error in that binary build)
My own source build made with the VS 2013 compiler, depending on MSVCP120.DLL and VCRUNTIME120.DLL
I was able to use both of these library binaries with my executable binary, when built with either:
VS 2013 compiler
VS 2015 compiler
My surprise of the success of using the library like described above, without any error, is caused by:
reading all over the internet about how C++ libraries and interfaces are not binary compatible (ABI) between different compiler versions, and thus cannot be used together with binaries built with other compilers. Exceptions: usage through C interfaces, which maintain the ABI compatibility; COM libraries (COM interfaces were built to overcome the same issue).
Using binaries built with different compilers can raise problems because of function name mangling (may be solved by the import library?!), dynamic memory allocation and freeing done by different versions of the allocators/destructors.
Can anyone provide some insight on this use case, on why I successfully managed to use a VS 2013 built dynamic library together with a VS 2015 toolset application without any of the above described problems? Also, the same applies when using the pre-built binary both with a VS 2013 build and a VS 2015 build of my 3D engine application.
Is it an isolated case or does the Assimp library itself take care of the problems and is implemented in such a way to ensure compatibility?
The actual usage of the library was pretty straightforward: I used a local stack variable of an Importer object (class) and from there on manipulated and read information from a bunch of structs; no other classes (I think)
As long as all the classes and memory used in the DLL is allocated and freed and maintained inside the class, and you don't use standard library container objects across the interface boundary you are completely safe to do it.
Even the use of std:string isn't allowed across DLL boundaries if the modules use different compilers or even have a different CRT usage, or at least a different CRT.
In fact, using plain interfaces (pure virtual classes) is safe for all VS C++ compilers. Also using extern "C" is safe.
So if the structures you exchange are just PODs or have simple plain data objects, and as long as allocation and destruction is done all inside the DLL you are free to mix and use DLLs build with different compilers.
So the best examples are the DLLs of the windows OS. They use a clearly defined interface of simple data structures. Memory management and allocation (like windows, menus, GDI objects) is done via a transparent handle. The DLLs are just blackboxes for you.
Hope that I met all points.

Can C++ libraries compiled with VC10 (sp1) be linked by code compiled with VC11?

The question says it all.
I understand that VC11 is currently only in beta, but what I'm asking is:
experience with trying to link with a closed source (widely used if possible) library compiled with vc10
specifications from Microsoft saying explicitely if yes or no the vc11 will be able to link with vc10 libraries.
I'm talking about C++ case only.
You may want to read this answer for the case of dynamic linking.
Regarding static linking, I think you can't safely link C++ libraries written with VCx with code compiled with VCy. For example, STL containers implementations change from version to version (and even within the same version, there are changes between debug and release mode, and settings like _HAS_ITERATOR_DEBUGGING, etc.).
Quoting VC++ STL maintainer:
The STL never has and never will guarantee binary compatibility
between different major versions. We're enforcing this with linker
errors when mixing object files/static libraries compiled with
different major versions that are both VC10+ [...]
That's a resounding no! Every major release of VS has a new version of the dynamic CRT, names are msvcr90.dll for VS2008, msvcr100.dll for VS2010, msvcr110.dll for VS11.
Using the dynamic CRT (/MD compile option) is important when you return C++ objects like std::string from an exported function, or otherwise return any pointer that needs to be deleted by the client code. That can only work properly when the client code is using the exact same version of the CRT as the DLL. Implicit is that this won't be the case when these chunks of code each have their own dependency on a msvcrXXX.dll version, they'll inevitably have incompatible CRT versions that don't share the same heap allocator.
You can write DLLs that are safe to use with any CRT version but that requires carefully crafting the API so that these dependencies do not exist. The COM Automation model is an example of that.
For dynamic libraries, there should be no problem, as they follow well-defined ABIs. You can link to dll's from any compiler, any time.
Static libraries are trickier. As far as I know, Microsoft has never guaranteed cross-compiler compatibility for those. In particular, features such as link-time code generation have been known to break compatibility between earlier releases. .lib files do not have a single well-defined format like DLLs do.
It might work, because Microsoft rarely breaks compatibility unless they have to, but as far as I know, it is not guaranteed.
Of course, if the actual functions and types exposed by the DLLs don't match up, you'll run into problems.
In VC11, the sizes of almost all standard library data structures have been changed (Microsoft finally employs the empty base class optimization, effectively reducing the size of all containers which use the default allocator.), so trying to pass a std::string from a DLL compiled with VC10 into a module compiled by VC11 will certainly break.
I don't see any reason why they could be incompatible. No matter what C++ compiler you have used to produce LIB files as soon as they follow format specification. You could check this question if you are interested in details of format.

C++ Dynamic Library Compiling/Linking

I know that if I link my c++ program to a dynamic library (DLL) that was built with a different version of Visual Studio, it won't work because of the binary compatibility issue.
(I have experienced this with Boost library and VS 2005 and 2008)
But my question is: is this true for all versions of MSVS? Does this apply to static libraries(LIB) as well? Is this an issue with GCC & Linux as well? and finally how about linking in VS to a DLL built with MinGW?
By the way aside from cross-platform or cross-compiler, why can't two version of the same compiler(VS) be compatibile?
Hi. I know that if I link my c++ program to a dynamic library (DLL) that was built with a different version of Visual Studio, it won't work because of the binary compatibility issue. (I have experienced this with Boost library and VS 2005 and 2008)
I do not remember ever seeing MS changing the ABI, so technically different versions of the compiler will produce the same output (given the same flags (see below)).
Therefore I don't think this is not incompatibilities in Dev Studio but changes in Boost.
Different versions of boost are not backwards compatible (in binary, source they are backward compatible).
But my question is: is this true for all versions of MSVS?
I don't believe there is a problem. Now if you use different flags you can make the object files incompatible. This is why debug/release binaries are built into separate directories and linked against different versions of the standard run-time.
Does this apply to static libraries(LIB) as well?
You must link against the correct static library. But once the static library is in your code it is stuck there all resolved names will not be re-resolved at a later date.
Is this an issue with GCC & Linux as well?
Yes. GCC has broken backwards compatability in the ABI a couple of times (several on purpose (some by mistake)). This is not a real issue as on Linux code is usually distributed as source and you compile it on your platform and it will work.
and finally how about linking in VS to a DLL built with MinGW?
Sorry I don't know.
By the way aside from cross-platform or cross-compiler, why can't two version of the same compiler(VS) be compatibile?
Well fully optimized code objects may be compressed more thus alignment is different. Other compiler flags may affect the way code is generated that is incompatible with other binary objects (changing the way functions are called (all parameters on the stack or some parameters in registers)). Technically only objects compiled with exactly the same flags should be linked together (technically it is a bit looser than that as a lot of flags don't affect the binary compatibility).
Note some libraries are released with multiple versions of the same library that are compiled in different ways. You usually distinguish the library by the extension on the end. At my last job we used the following convention.
libASR.dll // A Sincgle threaded Relase version lib
libASD.dll // A Single threaded Debug version
libAMR.dll // A Multi threaded Release version
libAMD.dll // A Multi threaded Debug version
If properly built, DLLs should be programming-language and version neutral. You can link to DLLs built with VB, C, C++, etc.
You can use dependency walker to examine the exported functions in the dll.
To answer part of your question, GCC/Linux does not have this problem. At least, not as often. libstdc++ and glibc are the standard C++/C libraries on GNU systems, and the authors of those libraries go to efforts to avoid breaking compatibility. glibc is pretty much always backward compatible, but libstdc++ has broken ABI several times in the past and probably will again in the future.
It is very difficult to write stable ABIs in C++ compared to C, because the automatic features in C++ take away some of the control you need to maintain an ABI. Especially once you get into templates and inline functions, where some of the code gets embedded in your application rather than staying contained in the shared library. That means that the object's structure can't ever change without requiring a recompilation of the application.
In practice, it isn't a huge deal on Windows. It would be fantastic if Microsoft just made the MSI installer know how to grab Microsoft-provided DLLs from Windows Update when an app is installed that needs them, but simply adding the redistributable to an InnoSetup-generated installer works well enough.

Are C++ libs created with different versions of Visual Studio compatible with each other?

I am creating a open-source C++ library using Visual Studio 2005. I would like to provide prebuilt libs along with the source code. Are these libs, built with VS2005, also going to work with newer versions of Visual Studio (esp VS Express Edition 2008)? Or do I need to provide separate libs per VS version?
Not normally, no. Libraries built with the VS tools are linked into the 'Microsoft C Runtime' (called MSVCRT followed by a version number) which provides C and C++ standard library functions, and if you attempt to run a program that requires two different versions of this runtime then errors will occur.
On top of this, different compiler versions churn out different compiled code and the code from one compiler version frequently isn't compatible with another apart from in the most trivial cases (and if they churned out the same code then there would be no point having different versions :))
If you are distributing static libraries, you may be able to distribute version-independent libraries, depending on exactly what you are doing. If you are only making calls to the OS, then you may be OK. C RTL functions, maybe. But if you use any C++ Standard Library functions, classes, or templates, then probably not.
If distributing DLLs, you will need separate libraries for each VS version. Sometimes you even need separate libraries for various service-pack levels. And as mentioned by VolkerK, users of your library will have to use compatible compiler and linker settings. And even if you do everything right, users may need to link with other libraries that are somehow incompatible with yours.
Due to these issues, instead of spending time trying to build all these libraries for your users, I'd spend the time making them as easy to build as possible, so that users can can build them on their own with minimal fuss.
Generally it's not possible to link against libraries built with different compilers, different versions of the same compiler, and even different settings of the same compiler version and get a working application. (Although it might work for specific subsets of the language and std library.) There is no standard binary interface for C++ - not even one for some common platform as there are in C.
To achieve that, you either need to wrap your library in a C API or you will have to ship a binary for every compiler, compiler version, and compiler setting you want to support.
If your library project is a static library, then, you'll have to supply a build for every Visual Studio version that you want your users to be in. In the example you gave, that equates to providing both a VS2005 and a VS2008 library.
If your library project is a dynamic library, then, you evade the problems somewhat, but, it means that users will need to make sure that they use the 'Microsoft C Runtime' that's compatible with your build environment. You can eliminate that criteria should you statically link the 'Microsoft C Runtime' into your dynamic library.