Ticket #10884 (closed defect: invalid)
LNK2005 linker errors when wxUSE_STL and an external module uses std::vector<int>
| Reported by: | hajokirchhoff | Owned by: | vadz |
|---|---|---|---|
| Priority: | high | Milestone: | 2.9.5 |
| Component: | base | Version: | |
| Keywords: | LNK2005 _WX_DECLARE_BASE_ARRAY stl | Cc: | troelsk@… |
| Blocked By: | Patch: | yes | |
| Blocking: |
Description
This is with wxMSW, Visual Studio 2008, svn approx 10 months old.
Summary:
#define wxUSE_STL 1 prevents using std::vector<int> in non-wxwidgets modules when trying to link to wxWidgets dynamically. It causes several LNK2005 std::vector<int>::~vector<int> already defined in wxbase*.dll
Bug:
If #define wxUSE_STL 1, then wxbase*.dll exports all std::vector<T> members where T is short, int, double and a lot of others. This clashes with any module using std::vector<T> that attempts to link wxWidgets dynamically. I haven't tried static linking.
IOW, it is not possible to use std::vector<T> in my own code and dynamically link to wxWidgets when T is one of (int, double, short etc...)
Here are the details and a suggested fix:
The problem is dynarray.h, WX_DECLARE_BASE_ARRAY_2
#define _WX_DECLARE_BASEARRAY_2(T, name, predicate, classexp) \
classexp name : public std::vector<T> \
This will expand to
class WXDLLIMPEXP wxBaseArrayInt:public std::vector<int> ...
with WXDLLIMPEXP = __declspec(dllexport)
Experimenting with Visual Studio I found that if I dllexport a class that derives from a template, the linker will instantiate all template members and dllexport them as well.
So in this case all std::vector<int> members will be instantiated (code generated for them) and exported.
When a completely different module (DLL) uses the same template, the instantiated methods will clash with the exported ones from the wxbase*.dll and a linker error LNK2005 (function already defined in foo.obj) prevents linking.
Solution:
Instead of exporting the entire class, export only its members functions, so that the base class will not be exported.
Change DECLARE_BASEARRAY_2 to
#define _WX_DECLARE_BASEARRAY_2(T, name, predicate, classexp) \
class name : public std::vector<T> \
{ \
classexp name(); \
classexp size_t Count();
and so on.
This will expand to
class wxBaseArrayInt:public std::vector<int>
{
WXDLLIMPEXP wxBaseArrayInt();
WXDLLIMPEXP size_t Count();
I will prepare a fix and attach it to this ticket.

