Home > Mobile >  Exporting class template with out-of-body definitions from DLL with MinGW-w64
Exporting class template with out-of-body definitions from DLL with MinGW-w64

Time:05-15

I am facing trouble properly linking a trivial Windows executable to a trivial DLL with MinGW-w64 (based on GCC 11.3.0 from MSYS2) when class templates are involved. A minimal reproducer is as follows.

The complete code of the library (library.cpp) is

template <class T> class __attribute__((dllexport)) TestClass
{
    public:
        void member() { __builtin_printf("member from library\n"); }
        void other_member();
};

template class __attribute__((dllexport)) TestClass<int>;

template <class T> void __attribute__((dllexport)) TestClass<T>::other_member () {}

and I compile it using

g   -std=c  11 library.cpp -o library.dll -shared -Wl,--out-implib,library.dll.a -Wl,--output-def,library.def

The complete code of the program (program.cpp) is

template <class T> class __attribute__((dllimport)) TestClass
{
    public:
        void member() { __builtin_printf("member from program\n"); }
        void other_member();
};

extern template class __attribute__((dllimport)) TestClass<int>;

int main (void)
{
    TestClass<int> test;
    test.member();
    return 0;
}

and I compile it using

g   -std=c  11 program.cpp library.dll.a -o program.exe

The linking of the program to the DLL fails with undefined reference to TestClass<int>::member(). It turns out that the linking failure can be solved in two ways:

  1. The extern template statement in the program is commented out. Then the compiler uses the local version of the template and the program prints "member from program".
  2. The definition of TestClass<T>::other_member is commented out from the library. Then the program properly links to the TestClass<int>::member in the library and it prints "member from library".

I understand the first point, where the extern template is avoided and a local implicit instantiation takes place. This also happens when I compile the code with optimizations.

But the second point perplexes me. Why does the out-of-body definition of TestClass<T>::other_member break export of TestClass<T>::member?

Disclaimer: I am debugging someone else's program, so the design choices are not mine.

CodePudding user response:

As far as I'm aware:
In library.cpp there is no (explicit) instantiation of the class template, or the member function of said class.

template class __attribute__((dllexport)) TestClass<int>;

Would be an (explicit) 'template specialization forward declaration'... (Because of course it would).
Long story short, if (and that's a bold assumption) I'm right you just need to add {} after TestClass<int> to have the type "defined".

To answer:

Why does the out-of-body definition of TestClass::other_member break export of TestClass::member?

I'm even less confident. But why are you defining a member function of a specialization of TestClass?

  • Related