27 февр. 2009 г.

Qt/C++ Сборка своей dll под Windows

Описание буду вести о сборке библиотеки, которая использует Qt, но многие замечания будут актуальны и в общем случае.

Потребовалось собрать библиотеку собственных Qt компонент. Казалось бы всё просто - добавить пару строк в pro (qt project file):
TEMPLATE = lib
qmake сделает под текущую платформу Makefile.
Хорошо это до тех пор пока вся разработка ограничивается GNU/Linux, где shared objects не нуждаются в дополнительных танцах с бубнами в виде дополнительных директив кода.

При формировании динамической библиотеки под Windows, DLL, необходимо явно указать какие именно символы должны попасть в библиотеку - а месте использования необходимо их подключить.
Например, если есть класс
class Foo
{
public:
void foo();
}
для включения его в DLL необходимо написать
class __declspec(dllexport) Foo
{
public:
void foo();
}
при его использовании вне библиотеки данный класс должен выглядеть
class __declspec(dllimport) Foo
{
public:
void foo();
}

Чтобы привести это к какому-то удобоваримому виду лучше воспользоваться Qt макросами Q_DECL_EXPORT и Q_DECL_IMPORT, которые определены в qglobal.h:
#ifndef Q_DECL_EXPORT
# ifdef Q_OS_WIN
# define Q_DECL_EXPORT __declspec(dllexport)
# elif defined(QT_VISIBILITY_AVAILABLE)
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# endif
# ifndef Q_DECL_EXPORT
# define Q_DECL_EXPORT
# endif
#endif
#ifndef Q_DECL_IMPORT
# if defined(Q_OS_WIN)
# define Q_DECL_IMPORT __declspec(dllimport)
# else
# define Q_DECL_IMPORT
# endif
#endif
т.е Q_DECL_EXPORT для Q_OS_WIN это будет __declspec(dllexport), для других платформ это пустой define
чтобы класс корректно экспортировался/импортировался определим макрос MY_WIDGET_EXPORT:
#if defined(MY_EXPORT)
# define MY_WIDGET_EXPORT Q_DECL_EXPORT
#else
# define MY_WIDGET_EXPORT Q_DECL_IMPORT
#endif
и теперь всё, что нужно при сборке библиотеки, это чтобы был определён макрос MY_EXPORT: т.е либо добавить в опции сборки -DMY_EXPORT или добавить в pro следующую строку:
DEFINES += MY_EXPORT
Окончательный вид класса Foo:
class MY_WIDGET_EXPORT Foo
{
public:
void foo();
}

3 комментария:

Анонимный комментирует...

Опечатку посмотри в предпоследнем посте..

Анонимный комментирует...

Пардон, в 3м с конца коде..

Vladimir Dolzhenko комментирует...

2Анонимный:
не вижу опечатки - может ты что-то не то имеешь в виду, или не понял?