Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Templated Classes and Functions in a Shared Object/DLL

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

like image 622
Travis Gockel Avatar asked Jan 21 '10 15:01

Travis Gockel


1 Answers

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.

like image 131
xtofl Avatar answered Nov 10 '22 18:11

xtofl