Considering the following example:
widget.hpp:
#pragma once
#ifdef BUILDING_LIB
#define BOOST_WIDGET_DECL __declspec(dllexport)
#else
#define BOOST_WIDGET_DECL __declspec(dllimport)
#endif
class Widget
{
public:
BOOST_WIDGET_DECL
Widget();
BOOST_WIDGET_DECL
virtual void f();
};
widget.cpp:
#include "widget.hpp"
Widget::Widget()
{
}
void Widget::f()
{
}
main.cpp:
#include "widget.hpp"
int main()
{
Widget w;
Widget w2(w);
w.f();
}
It builds and links correctly in MSVC using the following commands:
cl /LD widget.cpp /Fe:widget.dll /DBUILDING_LIB
cl main.cpp /link widget.lib
However, it fails in MinGW GCC:
g++ -shared widget.cpp -o widget.dll -DBUILDING_LIB
g++ main.cpp -L. -lwidget
with the following link error:
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible ./widget.lib when searching for -lwidget
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\tmp\cc2HbjyL.o:main.cpp:(.rdata$.refptr._ZTV6Widget[.refptr._ZTV6Widget]+0x0): undefined reference to `vtable for Widget'
collect2.exe: error: ld returned 1 exit status
Examining the MSVC build reveals that it emits the vtable inside the client application when a class has a defined virtual function but is not itself marked with __declspec(dllexport): https://godbolt.org/z/odc7arefz
However, this does not occur in MinGW GCC builds, which instead expect the vtable to be defined inside the DLL (similar to the Itanium ABI): https://godbolt.org/z/hWa9dfr3v
Interestingly, MinGW Clang behaves like MSVC and emits the missing vtable: https://godbolt.org/z/1xYdcEv5v. The application links and runs correctly in MinGW Clang even when using the DLL built with MinGW GCC.
Possible solutions:
-
Mark the entire class with BOOST_FOO_DECL so that RTTI and the vtable are always exported. However, this triggers the C4251 warning in MSVC when the class contains member variables, requiring those types to be marked with BOOST_FOO_DECL as well. This becomes problematic for large class hierarchies because it effectively forces every class to be decorated.
-
Introduce a new macro, BOOST_FOO_SYMBOL_VISIBLE, which unlike BOOST_SYMBOL_VISIBLE that expands to nothing on MinGW GCC this new macro should expand to the same value as BOOST_FOO_DECL when MinGW GCC is detected. This would ensure the vtable is visible in MinGW GCC without affecting other compilers.
Considering the following example:
widget.hpp:widget.cpp:main.cpp:It builds and links correctly in MSVC using the following commands:
However, it fails in MinGW GCC:
with the following link error:
Examining the MSVC build reveals that it emits the vtable inside the client application when a class has a defined virtual function but is not itself marked with
__declspec(dllexport): https://godbolt.org/z/odc7arefzHowever, this does not occur in MinGW GCC builds, which instead expect the vtable to be defined inside the DLL (similar to the Itanium ABI): https://godbolt.org/z/hWa9dfr3v
Interestingly, MinGW Clang behaves like MSVC and emits the missing vtable: https://godbolt.org/z/1xYdcEv5v. The application links and runs correctly in MinGW Clang even when using the DLL built with MinGW GCC.
Possible solutions:
Mark the entire class with
BOOST_FOO_DECLso that RTTI and the vtable are always exported. However, this triggers theC4251warning in MSVC when the class contains member variables, requiring those types to be marked withBOOST_FOO_DECLas well. This becomes problematic for large class hierarchies because it effectively forces every class to be decorated.Introduce a new macro,
BOOST_FOO_SYMBOL_VISIBLE, which unlikeBOOST_SYMBOL_VISIBLEthat expands to nothing on MinGW GCC this new macro should expand to the same value asBOOST_FOO_DECLwhen MinGW GCC is detected. This would ensure the vtable is visible in MinGW GCC without affecting other compilers.