Windows/Build/Common problems

From KDE Community Wiki
< Windows‎ | Build
Revision as of 21:26, 15 December 2011 by *>Darkstar (some common compile problems, part #1)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Rationale

I tend to re-build KDE from scratch from time to time using Microsoft Visual Studio. And all the time, the same problems prevent MSVC from correctly compiling some source files.

I decided to put these problems (and a solution) into the Wiki because I'm probably not the only one having these problems (or is everyone else building on mingw? ;-)) so this page not only serves as a reference for myself but might even benefit others.

It might even encourage developers to avoid these problems in the first place

Common problems

DLL-Export of templated functions/classes

Consider the following piece of code (taken from calligra/kexi/kexiutils/utils.h, rev. 6c7551c)

//! A helper for automatic deleting of contents of containers.
template <typename Container>
class KEXIUTILS_EXPORT ContainerDeleter
{
public:
    ContainerDeleter(Container& container) : m_container(container) {}
    .....
}

looks like a pretty simple, templated class which will be exported in the DLL file. It even builds correctly on MSVC, and the result is a working DLL file.

However, some other project using this DLL will throw errors like the following on link (note that this is for a different function, not the one above, but I couldn't find the corresponding error amongst the thousands that were thrown):

field.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: class QList<class KexiDB::Field *>::const_iterator __thiscall QList<class KexiDB::Field *>::constEnd(void)const " (__imp_?constEnd@?$QList@PAVField@KexiDB@@@@QBE?AVconst_iterator@1@XZ)

The problem is that there is no such thing as a generic DLL export. Each function a DLL exports must be completely specified. This makes sense, since it makes quite a difference whether the function accepts a list of ints or a list of QObjects. That is why GCC ignores the "dllimport" in this case, and just instantiates the template in the compiled object.

However, MSVC tries to honor the DLLImport directive and thus cannot find the exact template specification that the user of the class needs. How could it, since at the time the DLL got compiled, the compiler can't possibly know if you'll ever need a "ContainerDeleter<int>" or maybe a "ContainerDeleter<std::string>". How about "ContainerDeleter<QObject>"? Or "ContainerDeleter<std::pair<std::list<int>, std::list<int> > >"?

That's why you get the error. And you can't even blame MSVC for that, it is perfectly possible that your DLL exports 20 different versions of the "ContainerDeleter<foo>" class, and there might be one for exactly the case you need. It probably should try and look for an import, and if it finds none, instantiate the template again. Feel free to file a feature request with Microsoft for that :)

Solution: simple. Just remove the FOO_EXPORT macro on all templated classes/functions in the .h file(s) and recompile the libraries (shouldn't be needed but just to make sure)

This problem might turn up slightly different, in form of the MSVC compiler error C2492:

error C2491: 'foo' : definition of dllimport function not allowed

This means that you have a function declaration similar to

int KDEFOO_EXPORT foo(int bar, int baz);

in your .h file, and (in the same file) the definition of that function

int foo(int bar, int baz)
{
  return bar+baz;
}

The compiler knows it has to import the foo function from a DLL, but then you tell it "hey, this btw. is the definition of foo". No wonder the poor compiler gets confused ;-)