[xsd-users] Compiling to multiple DLLs, duplicate symbols problem

Boris Kolpackov boris at codesynthesis.com
Wed Jan 13 09:37:49 EST 2010


Hi Greg,

Greg Carter <greg at permedia.ca> writes:

> Did a clean/rebuild on both and when I attempt to link the dependant 
> dll I get the duplicate symbols problem:
>
> 1>geocosmxmllibbasecpp.lib(geocosmxmllibbasecpp.dll) : error LNK2005:  
> "public: class xsd::cxx::tree::sequence<int,1> & __thiscall  
> xsd::cxx::tree::sequence<int,1>::operator=(class  
> xsd::cxx::tree::sequence<int,1> const &)"  
> (??4?$sequence at H$00 at tree@cxx at xsd@@QAEAAV0123 at ABV0123@@Z) already defined  
> in Compaction_custom.obj
> 1>geocosmxmllibbasecpp.lib(geocosmxmllibbasecpp.dll) : error LNK2005:  
> "public: __thiscall  
> xsd::cxx::tree::sequence<int,1>::~sequence<int,1>(void)"  
> (??1?$sequence at H$00 at tree@cxx at xsd@@QAE at XZ) already defined in  
> Illite_custom.obj

I finally got around to figuring out what's going on here. When you
dll-export a class that derives from a template instantiation, VC++ 
automatically exports this template instantiation. So let's say
we have a.cxx which compiles to a.dll and contains the following:

class A_EXPORT A: public std::vector<int>
{
  ...
};

In this case, a.dll will export both class A and std::vector<int>.
Now, let's say we have b.dll (or b.exe for that matter) which links
to a.dll and has b.cxx with the following code:

void f ()
{
  std::vector<int> x;
}

Let's also assume that std::vector<int>::~vector() is not inline. In
this case, when we try to link b.dll, we will get duplicate symbols 
because ~vector() is exported from a.dll and is instantiated in b.cxx.
This works the way it does because b.cxx doesn't know anything about
a.cxx and, as a result, the VC++ compiler has no idea that the
vector<int> symbols should be imported instead of instantiated. If
we had something like this instead:

#include a.hxx // Declared class A above.

void f ()
{
  std::vector<int> x;
}

Then everything would work without any problems since the compiler
would automatically recognize std::vector<int> as imported. Here is 
an MSDN article that describes a similar situation:

http://msdn.microsoft.com/en-us/library/ms174286.aspx

Based on this understanding I was able to work around the problem
in your case by adding the following code at the end of exportxml.h:

#include <xsd/cxx/tree/containers.hxx>

namespace xsd
{
  namespace cxx
  {
    namespace tree
    {
      template class __declspec(dllimport) sequence<int>;
    }
  }
}

This basically tells VC++ to assume the symbols for sequence<int>
will be provided since geocosmxmllibbasecpp.dll contains an exported
class that derives from sequence<int>.

I am still think whether something can be done in the generated code 
to resolve this automatically but it doesn't look promising since this
involves translation units that don't know anything about each other.

Boris



More information about the xsd-users mailing list