C++ symbol export for class extending template class - c++

I'm working on a C++ project built with Visual Studio 2008.
I'm defining (in a project producing a dll) a template class and a derived, not-template, one:
template <class T>
struct DLL_EXPORT Base {
int base() { return 1; }
};
struct DLL_EXPORT Deriv: public Base<Deriv> {
int deriv() { return 1; }
};
the DLL_EXPORT is the usual stuff:
#ifdef COMPILING_MY_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
Now, when I'm trying to use my Deriv class in another project, the trouble is starting. If I use only the function from Deriv, it works well:
Deriv d;
d.deriv();
But if I try to call d.base(), I get the following linker error:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: int __thiscall Base<struct Deriv>::base(void)" (__imp_?base#?$Base#UDeriv####QAEHXZ)
If, elsewhere in my dll code, I'm using the d.base() function, it works well, and the linker error disappear in the "user" project. And if I remove the template part (it's not really useful in my example, but in the real-life situation it is), everything is fine.
It looks like the function don't get compiled if it's not used, or something equivalent. Any idea ?
Thanks in advance.

don't use __declspec(dllexport) on template definitions since they are not exported (they are not real code until instantiated).
They are only in the header file for usage by sources. You can use __declspec(dllexport) on specializations of templates ,but you must instatiated those at least once in your DLL.

If that is your problem, you might be able to fix it by explicitly instantiating the template.
In one of the .cc files in your DLL (not header file), include your template definition and write:
template int Base<Deriv>::base();
This should force the compiler to put the code for Base<Deriv>::base() into that compilation unit so your linker can find it.

I don't know much about this, but I think you might be able to fix it by writing
template struct Base<Derive>;
somewhere in your source file. (or perhaps template DLL_EXPORT struct Base<Derive>;)

Related

LNK2019 constructor/destructor using C++ Dll

I am developping a C++ DLL with a C wrapper in order to use it in Python and C#. So I create on Visual Studio a project (DLL) to develop and compile it. No problem here. I even can use my DLL on Python without trouble.
But, on Visual, I want to create another project in the same solution as the DLL to test the DLL too.
So I created the second project (Win32 Windows Application), added the .h to the header files, added the link to the .lib file I added in the folder of the test project, but when I try to compile it, I have errors about LNK2019, beginning with the constructor:
error LNK2019: unresolved external symbol "public: __cdecl Projet::Projet(void)" (??Projet##QEAA#XZ) referenced in function main
DLL = Projet / Test = Projet_Test
Projet.h
#pragma once
#include "Projet_inc.h"
class Projet
{
public:
Projet();
~Projet();
int multiply(int arg1, int arg2);
int result;
};
Projet_inc.h
#ifdef PROJET_EXPORTS
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif
#define CALLCONV_API __stdcall
#ifdef __cplusplus
extern "C" // C wrapper
{
#endif
typedef struct Projet Projet; // make the class opaque to the wrapper
EXPORT Projet* CALLCONV_API cCreateObject(void);
EXPORT int CALLCONV_API cMultiply(Projet* pDLLobject, int arg1, int arg2);
#ifdef __cplusplus
}
#endif
Projet.cpp
#include "stdafx.h"
#include "Projet.h"
Projet::Projet() {}
Projet::~Projet() {}
int Projet::multiply(int arg1, int arg2) {
result = arg1 * arg2;
return result;
}
Projet* EXPORT CALLCONV_API cCreateObject(void)
{
return new Projet();
}
int EXPORT CALLCONV_API cMultiply(Projet* pDLLtest, int arg1, int arg2)
{
if (!pDLLtest)
return 0;
return pDLLtest->multiply(arg1, arg2);
}
Projet_Test.cpp
// Projet_Test.cpp : définit le point d'entrée pour l'application console.
//
#include "stdafx.h"
#include "Projet.h"
int main()
{
Projet object;
return 0;
}
On Visual, I select the test project as startup project for information. And I look a lot of posts on SO but I didn't find the solution for now. Thank you in advance.
You need to __declspec(dllexport) all functions that you want to call directly, not just the C ones.
In your example, you should be able to correctly call the C wrapper functions cCreateObject and cMultiply, as those were exported correctly, but you will not be able to call the underlying C++ functions like Projet::Projet() and Projet::~Projet().
You have two ways of solving this: You can change these functions to inline functions and move their implementation to the header. That way, the client project will no longer invoke the code from the DLL for those functions, but instead just compile the inline definitions directly itself. This is obviously not a sensible approach in general. Alternatively, mark your C++ member functions with __declspec(dllexport), just as you did with the C functions.
Note that Visual Studio has a tendency of breaking the C++ ABI between versions, so you need to make sure that the compiler version you used for compiling the dll is compatible with the one you used for compiling the client application. This is not an issue if both parts are compiled with the same Visual Studio version or if you stick with a plain C interface.
First, the error about the missing symbol EpsCndCoreDll seems to be out of context here and you should rather be getting a compile error about redefining struct as a class (class Projet).
Probably you need to use something like:
class Projet;
typedef Projet* PProjet;
and use PProject as the opaque handle further on.
You also need to export the Projet class like:
class EXPORT Projet
to be able to instantiate that class by a client or add a factory function that returns a reference.
Make sure that you have added the DLL reference to your DLL.

C++ template specialization in different dll produces linker errors

I have a third party dll that contains a template class with several specializations. I have my own specialization on Linux, trying to compile a windows dll however results in linker errors.
I tried around a bit and found out that the dllimport specification on the template header may be the cause and removing it would fix my problem. However I don't want to modify or copy the header since it could break with every update to the third party library.
Here is a minimal example to reproduce my problem
test.h - dll/so header:
#ifdef _WIN32
#ifdef EXPORT
# define LIB_EXPORT __declspec(dllexport)
#else
# define LIB_EXPORT __declspec(dllimport)
#endif
#else
# define LIB_EXPORT
#endif
template <typename A> class LIB_EXPORT Foobar
{
public:
virtual void helloWorld(){}
virtual ~Foobar(){}
};
test.cpp - dll/so impl:
#define EXPORT
#include "test.h"
template class __declspec(dllexport) Foobar<int>;
main.cpp - example program:
#include "test.h"
//explicit instanciation - does not help
template class __declspec(dllexport) Foobar<char>;
int main(int argc, char** argv)
{
Foobar<char> a;
a.helloWorld();
}
Is there a clean way to get a complete instantiation of Foobar in my executable ?
Compilers used: Visual Studio 2010, g++ mingw w64 4.9.1
I know you said that you dont want to modify the header since it could break the third party library updates, but the header that the template is defined in is not set up correctly. Hopefully you can get your vendor to modify their headers to be more import/export friendly.
The goal:
Define (export) a template specialization in a dll/so and then use (import) that specialization to your exe.
test.h
We dont want to only import or export every specialization of the template, so we remove the LIB_EXPORT from the class.
template <typename A> class Foobar {
...
}
We do want to import/export a specific specialization of the template however. We will forward declare the specialization and then explicitly instantiate it later in the compilation unit you want it to reside in.
Since you are also building with gcc, you will want to make use of the 'extern' keyword. Visual Studio 2010 does not implement it for templates.
#ifdef _WIN32
# define TEMPLATE_EXTERN
#ifdef EXPORT
# define LIB_EXPORT __declspec(dllexport)
#else
# define LIB_EXPORT __declspec(dllimport)
#endif
#else
# define TEMPLATE_EXTERN extern
# define LIB_EXPORT
#endif
The final forward declaration looks like
TEMPLATE_EXTERN template class LIB_EXPORT Foobar<int>;
test.cpp
We explicitly instantiate the template class here since our efforts in the header file have turned off the automatic instantiation features of the compiler.
#define EXPORT
#include "test.h"
template class Foobar<int>;
main.cpp
The default state of the headers is to implicitly instantiate the Foobar class with any type that is not int. The int specialization has been specifically tagged as 'export' on gcc and __declspec(dllimport) on win32. So you are able to make other specializations wherever you wish.
#include "test.h"
// explicit instantiation
template class Foobar<char>;
int main(int argc, char** argv)
{
Foobar<char> a;
a.helloWorld();
}

Static data in DLL

My problem is remarkably similar to this one: A class in a DLL has a static member. In this case, the static member is of Type QString (a QT type) and provides a name for the class. I provide the normal export on class level: __declspec(dllexport).
When I link the DLL with my class to another project and try to compile it, I get an "unresolved external symbol" error for the static data. I verified two things:
Dumpbin definitely reports the static data member to be exported by compiled DLL.
Actually, the static data member seems not to be used in the application which reports the error.
HEADER file (.h) in DLL is:
class __declspec(dllexport) MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
IMPLEMENTATION file (.cpp) in DLL is:
#include "MyClass.h"
MyClass::~MyClass() { }
const QString MyClass::JUST_A_NAME("call_me_al");
In contrast to already mentioned post, I avoided methods to be inline, e.g. implementation is obviously not in the header. The type, QString (see line 83 ff.), contains several inlines itself. May that cause the error?
EDIT: I added an import statement in the header of my application. It is located before any includes.
HEADER file (.h) in APPLICATION is:
class __declspec(dllimport) MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
The error remains the same:
error LNK2001: non resolved external symbol ""public: static class QString const MyClass::JUST_A_NAME" (?JUST_A_NAME#MyClass##2VQString##B)". <name of .obj file from application>
In your application header file you need to do two things.
When exporting, declare the definition __declspec(dllexport)
When importing, declare the definition __declspec(dllimport)
You obviously cannot do them both at the same time.
What you have to do is define a macro like this:
#ifdef __COMPILING_MYLIB
#define MYLIBAPI __declspec(dllimport)
#else
#define MYLIBAPI __declspec(dllexport)
#endif
Then declare your exports like this:
// mylib.h
class MYLIBAPI MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
Then, when compiling MYLIB, you pass -D__COMPLING_MYLIB to the compiler, which triggers the #if above.
That way, when compiling the library itself, the header file declares things as exports, but when compiling things which will use the library, they are declared as imports.

Linker error trying to call extern "C" function from dll

I'm trying to use a C++ class from a native .dll project in a C++/CLI .dll project. Visual Studio 2010, .NET Framework 3.5. So far this is what I have:
// This is a common macro:
#ifdef ISDLL
#define DLL __declspec(dllexport)
#else
#define DLL __declspec(dllimport)
#endif
NativeProject:
//INativeType.h:
class DLL INativeType {
public:
virtual void Foo() = 0;
};
//NativeType.h:
class DLL NativeType : public INativeType {
public:
virtual void Foo();
};
extern "C" DLL INativeType CreateNativeType();
//NativeType.cpp:
void NativeType::Foo() {}
extern "C" DLL INativeType* CreateNativeType() {
return new NativeType();
}
C++/CLI Project:
// Wrapper.h:
#include "INativeType.h"
ref class Wrapper {
INativeType* m_nativeType;
};
// Wrapper.cpp:
#include "Wrapper.h"
#include "NativeType.h"
// in some method:
m_nativeType = CreateNativeType();
This gives me the following linker error:
error LNK2028: unresolved token (...) "extern "C" class INativeType * __stdcall CreateNativeType(void)"" ... in Wrapper.obj
Also, although the functions are correctly exported in NativeProject.dll, as I verified it with DependencyWalker, the linker also gives this warning:
warning LNK4199: /DELAYLOAD:NativeProject.dll ignored; no imports found from NativeProject.dll
The C++/CLI project is configured to delay load NativeProject.dll and also includes NativeProject.lib in its linker options. At this point I don't know how to diagnose this linker error. What am I doing wrong?
Why don't you just let the C++/CLI project instantiate the class directly instead of with a factory method?
Besides that, it just looks like you are re-inventing COM (using objects through interfaces). I would just instantiate full-blown C++ classes or, if you really need it, use full-blown COM.
EDIT: Make sure the factory method's calling convention is the same in both the client and the DLL.

Unreferenced external symbol during DLL function call

I'm having problems in implementing a class in a DLL in the same way it is explained here
. I have my interface with all the methods declared as virtual, I have my class that implements the interface and I have the method that should create the object of the class. The problem is here, when I try to use it I get a "unreferenced external symbol" error. Why?
class IXYZ
{
virtual void XXX() = 0;
};
class XYZ : public IXYZ
{
void XXX();
}
#ifdef __cplusplus
extern "C" __declspec(dllexport) IXYZ* __stdcall GetIXYZ();
#endif
and I use it inside my win32 program with:
IXYZ *myvar = GetIXYZ();
In my exe program I've included the .h file of the dll
If you've correctly defined the function in the DLL, and it is exported properly, then the only plausible explanation is that there is something wrong with your use of the .lib file in the application that uses the DLL.