Multiply defined symbols when linking to a DLL
I'm building two DLLs - let's call them DLL_A and DLL_B. DLL_A builds as a standalone entity but DLL_B needs to link to the lib file for DLL_A (i.e. it imports some functionality from DLL_A). While linking DLL_B I see lots of errors taking the following form (bear in mind that port.cpp and port.h are source files in DLL_B:-
Quote:
DLL_A.lib(DLL_A.dll) : error LNK2005: "public: bool __thiscall std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::empty(void)const " (?empty@?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@QBE_NXZ) already defined in port.obj
I'm not sure if I'm reading that correctly but to me, it seems to be saying that some STL components are somehow getting exported from DLL_A (std::vector maybe?? Or std::string??) and that they conflict with similar objects already in port.obj. Sure enough, when I used dumpbin /EXPORTS on DLL_A there did seem to be some evidence that that was true. So my next step was to examine the source code for port.obj. Of course, strictly speaking I should be examining some code from DLL_A but it has hundreds of source modules so I figured that I should start by identifying whatever it is in DLL_B that's throwing up the conflict (since I at least know which module the conflict is in!).
When I examined the source files for port.obj, std::string seems to get used quite often - but fortunately I could only find one occurrence of std::vector.
In port.h it occurs here:-
Code:
class DLL_B_API Port : public boost::noncopyable
{
public:
// c'tors + d'tors
int get_connections (std::vector<std::string> &) const;
// rest of class
};
In port.cpp it occurs here:-
Code:
int Port::get_connections (std::vector<std::string> & c) const
{
if (!port_engine.available()) {
c.insert (c.end(), _connections.begin(), _connections.end());
return c.size();
}
return port_engine.get_connections (_port_handle, c);
}
Is there anything in there that would be causing the above linker error? It's entirely possible that I'm looking in the wrong place but I suppose I've got to start somewhere....
[Edit...] I just found a possible clue in one of the header files for DLL_A, where I found this class declaration:-
Code:
namespace PBD {
class DLL_A_API Searchpath : public std::vector<std::string>
{
// Whatever...
};
}
Might that be causing std::vector<std::string> to get exported?
Re: Multiply defined symbols when linking to a DLL
By defining the export at the class level, you are effectively exporting the whole of searchpath including the dependants that are accessible.
In the above case since you publicly derive SearchPath from std::vector, all public members from std::vector need to be exported as well or it would be impossible to do:
Code:
Searchpath p;
p.empty();
You've pretty much uncovered one of the cases where "lazy mode" exporting declspecs cause issues. And that is when you derive from a pure template class, then use that pure template class directly in a co-linked module.
Solutions:
1) make explicit overrides in Searchpath for each of the memberfunctions in std::vector (you could limit this to "any memberfunctions of std::vector you use in dll B"
2) use private inheritance (I'm not 100% sure this will work in this particular case)
3) don't derive searchpath from std::vector, make it a member of Searchpath instead
4) export members instead of the whole class.
Re: Multiply defined symbols when linking to a DLL
Thanks O'Reubens. I implemented your suggestion #4 and that fixed it. One question though... Here's how that class got declared in DLL_A:-
Code:
namespace PBD {
class DLL_A_API Searchpath : public std::vector<std::string>
{
// Whatever...
};
}
Shouldn't namespace PBD be helping me here? When I used dumpbin /EXPORTS to examine the DLL, all the various functions from class Searchpath were in namespace PBD - but the base class wasn't. Obviously, 'vector' and 'string' were in namespace std but it's definitely possible for namespaces to be nested - so why wasn't the base class effectively PBD::std::vector<std::string> :confused:
Re: Multiply defined symbols when linking to a DLL
Quote:
Originally Posted by
John E
so why wasn't the base class effectively PBD::std::vector<std::string> :confused:
Because there is no such class as PDB::std::vector<std::string>. The vector is in namespace std -- you can't attach it onto a "third-party" namespace and make it now myNamespace::std::vector.
Regards,
Paul McKenzie
Re: Multiply defined symbols when linking to a DLL
That makes sense Paul. Thanks. :thumb:
Re: Multiply defined symbols when linking to a DLL
don't have a compiler handy atm so can't test... but wouldn't
Code:
namespace PDB
{
#include <vector>
}
cause the vector to be PDB::std::vector<> ?
can't say I can find a good reason to do so for vector, but wrapping your own namespace around an include has been usefull at times to force a 3rd party header into a namespace to solve name colisions.