I have a Visual C++ solution, using Visual Studio 2017, which contains 5 projects:
In SpikeUtils, I have a header _SpikeEngineObject.h:
#pragma once
#ifdef DLL_SPIKEUTILS
#define SPIKEUTILS_EXPORT __declspec(dllexport)
#else
#define SPIKEUTILS_EXPORT __declspec(dllimport)
#endif
#include "GUID.h"
namespace SpikeUtils
{
class SPIKEUTILS_EXPORT _SpikeEngineObject
{
public:
const std::string & _SpikeEngineId()
{
return _SpikeRef.Value();
}
private:
SpikeUtils::GUID _SpikeRef = SpikeUtils::GUID::Generate();
};
}
The file GUID.h included looks like this:
#pragma once
#include <iostream>
#ifdef DLL_SPIKEUTILS
#define SPIKEUTILS_EXPORT __declspec(dllexport)
#else
#define SPIKEUTILS_EXPORT __declspec(dllimport)
#endif
namespace SpikeUtils
{
class SPIKEUTILS_EXPORT GUID final
{
public:
GUID(GUID const & other) = default;
GUID& operator=(GUID& other) = default;
static GUID Generate();
std::string const & Value();
private:
GUID(std::string const & value) : value(value)
{}
std::string value;
};
}
I am omitting the implementation of GUID.cpp because I don't think it's relevant.
Now, in SpikeUI, I have a class Drawable, that just inherits from _SpikeEngineObject.h
#pragma once
#include "_SpikeEngineObject.h"
#ifdef DLL_SPIKEUI
#define SPIKEUI_EXPORT __declspec(dllexport)
#else
#define SPIKEUI_EXPORT __declspec(dllimport)
#endif
namespace SpikeUI
{
namespace UI
{
struct SPIKEUI_EXPORT Drawable : SpikeUtils::_SpikeEngineObject
{
....
};
}
}
Obviously, all the respective DLL_ defines have been put inside each individual project's C/C++ -> Preprocessor -> Preprocessor definitions, so the projects should build with the appropriate dllimport / dllexport macro.
But when I try and build SpikeUI, I get linker errors like:
LNK2019 unresolved external symbol "__declspec(dllimport) public: __cdecl
SpikeUtils::_SpikeEngineObject::_SpikeEngineObject(void)" (__imp_??
0_SpikeEngineObject@SpikeUtils@@QEAA@XZ) referenced in function "public:
__cdecl SpikeUI::UI::Drawable::Drawable(enum SpikeUI::UI::DrawableType)" (??
0Drawable@UI@SpikeUI@@QEAA@W4DrawableType@12@@Z)
and
LNK2019 unresolved external symbol "__declspec(dllimport) public: __cdecl
SpikeUtils::_SpikeEngineObject::~_SpikeEngineObject(void)" (__imp_??
1_SpikeEngineObject@SpikeUtils@@QEAA@XZ) referenced in function "int
`public: __cdecl SpikeUI::UI::Drawable::Drawable(struct UI::Drawable::dtor$0
const &)'::`1'::dtor$0" (?dtor$0@?0???0Drawable@UI@SpikeUI@@QEAA@AEBU012@@Z@4HA)
An interesting fact is that Visual Studio even highlights which macro will be used, and for example GUID.h does highlight the dllexport macro, but _SpikeEngineObject.h highlights the dllimport macro for some reason.
Searching through SO and MSDN, it looks like this macro pattern should work, but for some reason it's not consistent on my project.
How can I solve the linker errors?
Answering my own question here:
The SpikeUI project has a dependency on the SpikeUtils project, and it is linked against the .lib and .dll project that is outputed by building the SpikeUtils project.
Now, the problem was that the class _SpikeEngineObject was a header-only class (ie no .cpp for the class). Hence, I am assuming that the SpikeUtils.lib did not contain any symbols for the constructor / destructor etc. of the _SpikeEngineObject, so the linker was having problems linking it.
I solved the problem by adding a .cpp file for the class and implementing dumb constructor / destructor so that the compiler would generate these symbols, and everything was fine.