views:

234

answers:

1

I am working on a fairly significantly-sized project which spans many shared libraries. We also have significant reliance on the STL, Boost and our own template classes and functions. Many exported classes contain template members and exported functions contain template parameters.

Here is a stripped-down example of how I do library exporting:

#if defined(_MSC_VER) && defined(_DLL)
    //    Microsoft 
    #define EXPORT __declspec(dllexport)
    #define IMPORT __declspec(dllimport)
#elif defined(_GCC)
    //    GCC
    #define EXPORT __attribute__((visibility("default")))
    #define IMPORT
#else
    //    do nothing and hope for the best at link time
    #define EXPORT
    #define IMPORT
#endif

#ifdef _CORE_COMPILATION
#define PUBLIC_CORE EXPORT
#define EXTERNAL_CORE
#else
#define PUBLIC_CORE IMPORT
#define EXTERNAL_CORE extern
#endif

#include <deque>

//    force exporting of templates
EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;

class PUBLIC_CORE MyObject
{
private:
    std::deque<int> m_deque;
};

SO, my problem is that when I compile in Visual Studio (both 2008 and 2010), I get the following warning:

warning C4251: 'std::_Deque_val<_Ty,_Alloc>::_Almap' : class 'std::allocator<_Ty>' needs to have dll-interface to be used by clients of class 'std::_Deque_val<_Ty,_Alloc>'

Which seems to imply that I haven't exported std::allocator<int>, which I have. And it's not like my exporting is incorrect, since not including

EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;

yields the warning:

warning C4251: 'MyObject::m_deque' : class 'std::deque<_Ty>' needs to have dll-interface to be used by clients of class 'MyObject'

The only thing I can think of is that the _Ty the warning about the std::allocator is talking about is somehow not int, but I can't seem to find any indication that it would be otherwise, since a std::deque<int> would logically allocate with an std::allocator<int>.

A consuming application can use the class just fine, but I have a gut feeling that this warning should not be ignored. When compiling with g++ in Linux, no errors are emitted (although that doesn't mean it's working right). Is g++ automatically doing something that MSVC cannot do? I've been targeting GCC on Linux, LLVM on OSX and MSVC on Windows, but I could potentially move to MinGW for Windows development, so abandoning MSVC is not exactly out of the question (if this proves to be too big of an inconvenience).

+2  A: 

As you may know, the templates in your export file are in fact a 'permission to fill in whatever you think necessary' for the compiler.

That means that if you compile your header file with compiler A, it may instantiate a completely different deque<int> than compiler B. The order of some members may change, for one, or even the actual type of some member variables.

And that's what the compiler is warning you for.

EDIT: addes some consequences to the explanation

So your shared libraries will only work together nicely when compiled by the same compiler. If you want them to work together, you can either make sure that all client code 'sees' the same declaration (through using the same stl implementation), or step back from adding templates to your API.

xtofl
+1: Not only the same compiler, but the same version of the same compiler. VS 2008 and VS 2008 SP1 could potentially have different implementations of and of the STL types, for example.
John Dibling
I was under the impression that statements like `EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;` were meant to force compilers compiling a consumer to use the original compiler's implementation of std::deque, through __dllimport. The containers are the only things I'm really having a problem with (since exporting of things that aren't as complicated seems to work fine).
Travis Gockel
@Travis: How would a target compiler know what the original implementation of std::deque is, for example?
John Dibling
@John: I see your point...I'm beginning to see what actually happens when one declares `extern template class __declspec(dllimport) std::deque<int, std::allocator<int> >`. It seems like `std::vector<T>` is the only export that actually works, which is inconvenient.
Travis Gockel
@Travis: Even std::vector doesn't really 'work'. I will elaborate on this a bit more...
John Dibling