Home Page
Archive > Posts > Tags > DLLs
Search:

Virtual Functions in DLLs
And Shared Object Visibility

Since I am now working on making sure all my applications work in both Windows and Linux, I have been having to work a lot more with GCC recently (which I am basically totally switching too). It’s a bit trying having to learn an entirely different toolset after having used the same formula for many many years.

Linux shared objects are a bit different than Window’s DLLs in that all symbols are naturally exported instead of just the ones you specify, among other different behaviors like how the libraries are loaded and unloaded during runtime. The solution to the visibility problem is more recent as far as GCC goes, and is to use the visibility attribute. Symbol visibility in a shared library is very important for both symbol collision and library load time reasons. This means, however, that every functions/symbol needs to be marked as either not visible (for Linux), or exportable (for Windows).


I ran into a rather nasty problem however that I couldn’t find any information on when making a class exportable in a DLL. Basically, I had the following:


A.dll creation
A.h
//Determine whether we are exporting or importing functions from this DLL
#undef DLLEXPORT
#ifdef A_DLL
	#define DLLEXPORT __declspec(dllexport)
#else
	#define DLLEXPORT __declspec(dllimport)
#endif

DLLEXPORT class a
{
	public:
	int x;
	void a_foo();
	virtual void a_bar();
};
A.cpp
#define A_DLL
#include "A.h"
#include "stdio.h"
void a::a_foo() {printf("a_foo");}
void a::a_bar() {printf("a_bar");}
Compiling A.dll
g++ -c A.cpp -o A.o
g++ -shared -Wl,--output-def=libA.def -Wl,--out-implib=./libA.a -Wl,--dll A.o -o ./A.dll

B.dll creation
B.h
//Determine whether we are exporting or importing functions from this DLL
#undef DLLEXPORT
#ifdef B_DLL
	#define DLLEXPORT __declspec(dllexport)
#else
	#define DLLEXPORT __declspec(dllimport)
#endif

DLLEXPORT class b
{
	public:
	int x;
	void b_foo();
	virtual void b_bar();
};
B.cpp
#define B_DLL
#include "B.h"
#include "stdio.h"
void b::b_foo() {printf("b_foo");}
void b::b_bar() {printf("b_bar");}
Compiling B.dll
g++ -c B.cpp -o B.o
g++ -shared -Wl,--output-def=libB.def -Wl,--out-implib=./libB.a -Wl,--dll B.o -o ./B.dll

main.exe creation
main.cpp
#include "A.h"
#include "B.h"

int main()
{
	a a_var;
	a_var.a_foo();
	a_var.a_bar();

	b b_var;
	b_var.b_foo();
	b_var.b_bar();
	return 1;
}
Compiling main.exe
g++ -c main.cpp -o main.o
g++ -c main.o -o ./main.exe -L./ -lA -lB

The problem that occurred was when only 1 of the DLL files was included on Windows, everything worked fine, but when both were included, I could only access the virtual functions from one of the 2. I was getting an error about “required class export or error due to vtable not being found”.

After many hours of tinkering and fruitless research, I stumbled upon the solution by accident. It turns out I was using the incorrect syntax. The classes should have been defined as “class DLLEXPORT x {}” instead of “DLLEXPORT class x {}”. Why it worked when only 1 of the DLLs was present, but clobbered with multiple DLLs, I have no idea.