вторник, 8 ноября 2011 г.

Сборка и установка визуальных плагинов Qt под Windows

В процессе работы с библиотекой Qt возникла необходимость создания своих визуальных компонент-плагинов для Qt Creator-а. Эта задача разделяется на следующие: создание класса визуального компонента (как правило, наследника QWidget); создание класса регистрации плагина в Qt Creator-е; обеспечение возможности сборки как release-, так и debug-версии программы, в которой используется данный плагин. Рассмотрим решение каждой из этих задач для Qt 2010.05 for Windows.
Создание класса визуального компонента происходит обычно, за исключением необходимости добавления одного макроса. Выглядит это приблизительно так:
#include <QWidget>
#include <QtDesigner/QDesignerExportWidget>
//-----------------------------------------------
class QDESIGNER_WIDGET_EXPORT NewClass : public QWidget
{
private:
public:
 explicit NewClass(QWidget* parent = 0);
 ~NewClass(void);
};

Саму реализацию, для простоты, не привожу, можно отнаследоваться от QPushButton, чтобы результат был более нагляден.
Класс QDesignerExportWidget через этот макрос обеспечивает доступ Qt Designer-а к создаваемому классу плагина, и позволяет создавать его экземпляры "на лету", в процессе "таскания мышкой компонентов".
Для регистрации плагина создаётся отдельный класс. Вот как может выглядеть его заголовочный файл:
#include <QtPlugin>
#include <QDesignerCustomWidgetInterface>
//-----------------------------------------------
#include "./NewClass.hpp" //Оба класса находятся в одном каталоге
//-----------------------------------------------
class NewClassPlugin : public QObject,public QDesignerCustomWidgetInterface
{
  Q_OBJECT;
  Q_INTERFACES(QDesignerCustomWidgetInterface);
private:
  bool initialized;
public:
  NewClassPlugin(QObject* parent = 0);
  bool isContainer(void) const;
  bool isInitialized(void) const;
  QIcon icon(void) const;
  QString domXml(void) const;
  QString group(void) const;
  QString includeFile(void) const;
  QString name(void) const;
  QString toolTip(void) const;
  QString whatsThis(void) const;
  QWidget* createWidget(QWidget* parent);
  void initialize(QDesignerFormEditorInterface* core);
};
//-----------------------------------------------

О "наполнении" этих функций можно посмотреть официальную документацию, никаких расхождений с ней не наблюдалось.
Теперь приступаем к сборке и установке плагина. Для ясности дальнейших действий немного о структуре разрабатываемого мной приложения, в котором будет использоваться плагин. Приложение состоит из загрузчика, и динамических библиотек-модулей, которые он загружает, предоставляя некое внутреннее API для функционирования. Как загрузчик, так и модули расположены в индивидуальных поддиректориях общей директории проекта. В директории плагина (пусть её название -- newPlugin) создаём файл проекта newPlugin.pro со следующим содержимым:
TEMPLATE = lib
TARGET = $$qtLibraryTarget($$TARGET)
CONFIG += designer plugin
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer

DLL = $$TARGET".dll"

CONFIG(release, debug | release): QMAKE_POST_LINK = xcopy \
.\\release\\$$DLL ..\\loader\\release /Y

CONFIG(debug, debug | release): QMAKE_POST_LINK = xcopy \
.\\debug\\$$DLL ..\\loader\\debug /Y

# Input
HEADERS += ./newClass.hpp \
           ./newClassPlugin.hpp

SOURCES += ./newClass.cpp \
           ./newClassPlugin.cpp

target.path = $$[QT_INSTALL_PLUGINS]/designer
sources.files = $$HEADERS $$SOURCES *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/designer/newClass
INSTALLS += target sources

В строке 6 определяется переменная с именем создаваемой DLL, которое будет различным для release- и debug-версий. Строки 8-9 и 11-12 производят копирование средствами Windows собранных DLL плагина в соответствующие каталоги загрузчика. После выполнения команд qmake и mingw32-make all нужно произвести установку собранного плагина в соответствующие каталоги Qt Creator-а. Поскольку он собран, как release-версия, то установка производится командой mingw32-make release-install. Удаляется плагин, соответственно, командой mingw32-make release-uninstall.
И заключительный этап -- сборка модуля, использующего плагин. Поскольку в модуле будет использоваться форма, созданная с помощью Qt Creator-а, то явное подключение заголовочного файла плагина не потребуется. Для модуля создаём файл проекта moduleName.pro:
TEMPLATE = lib
TARGET = 
DEPENDPATH += .
INCLUDEPATH += . $$[QT_INSTALL_EXAMPLES]/designer/newPlugin
CONFIG += thread dll rtti stl exceptions

CONFIG(release, debug | release): LIBS += \
-L"../newPlugin/release" -lnewPlugin

CONFIG(debug, debug | release): LIBS += \
-L"../newPlugin/debug" -lnewPlugind

# Input
FORMS += ./formWithPlugin.ui

HEADERS += ./module.hpp

SOURCES += ./module.cpp

Здесь в строке 4 происходит задание директории, в которой находятся заголовочные файлы плагина. Строки 7-8 и 10-11 задают линковку для отладочной (-lnewPlugind) и релизной (-lnewPlugin) версий. В строке 14 подключается файл описания формы, созданной Qt Creator-ом. Выполнив команды qmake и mingw32-make all, получаем работающий и в release-, и в debug-версиях плагин.

Upd. По неясной пока причине статические библиотеки плагина начали собираться с постфиксом 4, т.е. вместо -lnewPlugin создаётся -lnewPlugin4. В файл проекта, использующего плагин, следует внести соответствующие изменения.