Redistribute a dynamic library: c++ in header and issues when mixing compilers
-
Hi neFast,
the big difference between C++ and C is how things are exported. This also depends on the tool chain (MSVS6, 2005 use different C++ exports, Mingw also, ...).
The only exports that are really independent are pure C exports, which means functions with parameters which then can be retrieved by GetProcAddress.
If you need to export class, you have no chance of doing it in a C way and it will be compiler dependent.
-
@leon: I think he will use mingw to compile his program and import my dll compiled with msvc.
@Gerolf: So basicaly we should never export a class in a dll? What part of the resulting binary could be compiler dependant, and what kind of issues could we get?
(do you have links to online doc on this subject?)Thanks for your help guys!
-
The main issues are with name mangling (have a look at the weird function names when you have linker errors), which is different for practically every tool chain. There is no real reason to avoid C++ in your library exports unless you want to serve all compilers with one build. If Qt would be avoiding C++ exports in their dll's we would be working against a pure C interface, but that means Qt have to go the extra mile to support other compilers as well.
If you want to provide C++ in your interface, just make sure you cover the compilers the other developer might use with a build for that specific one.
There is also the issue of calling conventions (stdcall, cdecl, fastcall, thiscall, whatever), which is not standardized either. For C linkage, everything is standardized. I don't think the C++ guys addressed this in c++0x either, but we'll see (would be great if they did).
-
Hum, you example with Qt looks like a counterexample, doesn't it?
There are a mingw and a msvc precompiled version of Qt. Maybe for this reason, no? -
[quote author="neFAST" date="1304105450"]Hum, you example with Qt looks like a counterexample, doesn't it?
There are a mingw and a msvc precompiled version of Qt. Maybe for this reason, no?[/quote]You got my point exactly. However, this broad support for multiple compilers leads to a lot of builds, which is the approach taken by Qt. If you don't want that, you should go for C linkage. -
And what step in C++ code compilation cause this problem that I won't have with pure C?
I know google is my friend but maybe you know a nice place where I should learn a bit more about c++ compilers.
Thanks again for your help. -
"Binary compatibility":http://rlc.vlinder.ca/blog/2009/08/binary-compatibility/
-
[quote author="neFAST" date="1304106257"]And what step in C++ code compilation cause this problem that I won't have with pure C?
I know google is my friend but maybe you know a nice place where I should learn a bit more about c++ compilers.
Thanks again for your help.[/quote]Inside the MSVS tool chain, you also have to use the same version (MSVS 2005 or MSVS 2005 SP1 or MSVS 2008 or MSVS 2008 SP1 or MSVS 2010) as all of these versions use different msvcrt dlls. msvcrt is the microsoft C-runtime lib which implements all the heap and memory stuff. If you mix them using Qt (where the responsibility of deleting memory goes from binary to binary), you program will crash.
There, name mangling etc would work, but heap management not between the versions of the MSVS:-(
-
That's why they call it "DLL hell":http://en.wikipedia.org/wiki/DLL_hell...
-
Thanks again for your links.
Anyone has a nice example of a good and smart pure C exports implementing something class-like? -
Read through "Building Your Own Plugin Framework":http://drdobbs.com/cpp/204202899?pgno=1.
-
[quote author="neFAST" date="1304320729"]Thanks again for your links.
Anyone has a nice example of a good and smart pure C exports implementing something class-like?[/quote]If you need classes, you need C++,
Otherwise something like functions that get handles (which might be internal class pointers).
Then all parameters in the functions must be C-parameters (pods or structs, no QString, STL, etc) -
You can of course do something like
@ typedef struct Object {
void (*setData)(struct Object *, int);
int (*data)(struct Object *);
int m_data;
} Object;Object *objectConstructor()
{
Object *o = malloc(sizeof(Object));
memset(o, 0, sizeof(Object));
o->setData = objectSetData;
o->data = objectData
return o;
}void objectSetData(Object *this, int data)
{
this->m_data = data;
}int objectData(Object *this)
{
return this->m_data;
}
@But that would arguably obscure your code for the simple fact that you have to explicitly pass the this argument:
@
Object *o = objectConstructor();
o->setData(o, 5);
printf("%d\n", o->data(o));
@
thereby making the function pointers look rather awkward.