Converting STL heavy static library to shared

Started by
4 comments, last by King Mir 9 years, 8 months ago

I've got a static library that's pretty STL heavy that I need to convert to a shared library. I've heard a lot of things about STL being bad in shared libraries, but none of the topics I could find really mentioned a couple specifics I was wondering about.

If the STL usage is kept to the library's implementation and is only used internally for implementation, then would it still introduce problems? Also, some of the methods take a reference to a vector and fill it with objects, am I going to be forced to roll my own data structures for these cases? And same with areas where strings need to be returned and/or passed (some I might be able to get away with converting to C-style strings, but an actual string class would be much better).

Advertisement

Also, some of the methods take a reference to a vector and fill it with objects, am I going to be forced to roll my own data structures for these cases? And same with areas where strings need to be returned and/or passed (some I might be able to get away with converting to C-style strings, but an actual string class would be much better)

These sound like parts of the public API, not the internal implementation?
If so, yes, they will cause problems unless the program that uses the DLL is built with the exact same compiler and the same compiler-settings.

If you're using a different compiler, and/or different settings, then the DLL and the program that use it might have two different implementations of the STL -- so the DLL's idea of how a "std::string" works might be different than what the EXE expects, etc...

Also, it's possible that the DLL will use new (inside a string/vector/etc) and the EXE will then use delete. This can cause issues if they are using different heaps / different versions of the STL...

On Windows, you can avoid this problem by making sure that you're using the DLL version of the STL, e.g. http://i.imgur.com/ARYDZcz.png

Reiterating, the problem is not about if the library is static or dynamic or any such things. The problem ensuring safe conditions when crossing boundaries.

If you say "here is a pointer to a c-style string" or "here is a 32-bit value" there are no problems. Data is transferred and read, but as long as each side is responsible for their own internal work everything works just fine.

When you start to pass around larger objects there is potential for problems. One side might have some build-specific data members (like debug variables) so that the two structures are not identical, one may have 16 data members but the other has 18. As long as the data members and the layout match, most of those concerns go away. If you end up modifying a shared data structure you need to rebuild everything on both sides to keep them in sync, but in the grand scheme of things this is not a problem.

The other big issue is when you pass around things that rely on other systems, like memory management. If one side is using a certain memory manager, and the other side is using a different memory manager, and then both sides are attempting to manipulate the memory, the two will behave in incompatible ways and really bad things are going to happen. Most of the container classes are a great example of this. Since container classes tend to have their functions get inlined and container classes can modify large blocks of memory, programmers must be careful that both sides are using compatible functions. One side uses a debug allocator that puts a nice little border around it and tracks the memory, then the other side resizes the memory with a non-debug allocator and releases the debug-tracked block with a non-debug function and suddenly all kinds of nightmare scenarios can play out. Memory management is probably the most common item, but it applies to any set of functions. If one side behaves in a way that is incompatible with the other side, errors will result.

As long as both sides (the main executable and the external libraries) are compiled with the same settings and the same combination of libraries everything is fine. The data structures will be the same size, with the same alignment, and they'll be using the same libraries for external functionality.

As long as both sides (the main executable and the external libraries) are compiled with the same settings and the same combination of libraries everything is fine. The data structures will be the same size, with the same alignment, and they'll be using the same libraries for external functionality.


The simple common case here is that if you're talking about a shared library you ship with your game's executable, you most likely don't need to worry about it.

Sean Middleditch – Game Systems Engineer – Join my team!


If the STL usage is kept to the library's implementation and is only used internally for implementation, then would it still introduce problems?
If you are 100% certain that the STL usage of the shared library is only internal, then you are ok in theory. In reality, that is usually pretty hard to isolate and it takes some serious dedication to make sure non of your interface exposes STL types in any way. In addition, the types of bugs that can be produced with this include memory corruption which can be notoriously difficult to track down.

My advice is that unless you are absolutely certain that you need a shared library, stick with a static library. If you must use a shared library, make sure that your projects are always compiled in tandem with the same settings. If you are using Visual Studio, this is pretty easy to do with the configuration management system, but easy to mess up if you manually introduce compilation flags in one project but not in the others.

As long as your shared library doesn't expose STL containers as part of its interface, there's no problem. So you do want to roll your own types for passing data in and out.

Then you have to make sure your library has a stable ABI itself while still being amendable to bug fixes and expansion. This is mainly done by using the PImpl pattern. The details of what you can change while maintaining ABI compatibility is different between MSVS and Gcc.

This topic is closed to new replies.

Advertisement