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:
- 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".
- The definition of
TestClass<T>::other_member
is commented out from the library. Then the program properly links to theTestClass<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
?