Search code examples
c++visual-studiodllshared-librariesassimp

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)


Solution

  • 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.