Evgenii Legotckoi
Evgenii Legotckoi9. Oktober 2018 15:16

Qt/C++ - Tutorial 083. Dynamische Bibliothek erstellen und mit einem anderen Projekt verbinden

Im Forum tauchte die Frage auf, wie man eine dynamische Bibliothek erstellt und korrekt mit einem Drittprojekt verbindet. Solche Fragen tauchen regelmäßig auf, also betrachten wir eine Option, nämlich das Erstellen einer dynamischen DLL-Bibliothek für Windows mit den Standardassistenten in Qt Creator.

In diesem Fall wird die Option nicht berücksichtigt, wenn das Projekt in Teilprojekte aufgeteilt wird, die als Bibliotheken zusammengestellt und dann mit dem Hauptprojekt verbunden werden. Da dies dynamische interne Bibliotheken des Projekts sein werden. Lassen Sie uns eine externe Bibliothek erstellen, die theoretisch in Form von Binärdateien verteilt werden kann.

Lassen Sie uns zwei Projekte erstellen:

  1. QuiLib – Dies ist eine externe dynamische Bibliothek, die ein Dialogfeld enthält. Dieses Dialogfeld wird im Hauptprojekt geöffnet.
  2. WithDynamicLibrary – das Projekt, das nur zum Verbinden dieser dynamischen Bibliothek verwendet wird.

Schritt 1

Lassen Sie uns die Projekterstellung im Qt Creator-Menü auswählen und den Typ unseres Projekts auswählen. Es wird eine C++ Bibliothek sein.

Schritt 2

Schreiben wir den Namen des Projekts und seinen Standort auf

Schritt 3

Lassen Sie uns Kits für den Aufbau des Projekts auswählen.

Hier gibt es einen sehr wichtigen Punkt, den Anfänger vergessen können. Wenn Sie ein Projekt mit einem Compiler einer bestimmten Version erstellen, können Sie diese Bibliotheken nur in einem Projekt verwenden, das von einem Compiler derselben Version erstellt wird.

Ich erstelle diese Bibliothek mit dem Compiler MSVC2017.

Schritt 4

Wählen Sie die gewünschten Module aus. Für unsere Bibliothek reicht die Grundfunktionalität aus.

Schritt 5

Geben wir der Bibliotheksklasse, die darin verwendet wird, einen Namen. Der Name ist in diesem Fall derselbe wie der Name der Bibliothek selbst. Aber du kannst dich ändern. Es ist nicht wesentlich.

Schritt 6

Verwenden Sie ein Versionskontrollsystem? Fügen Sie also das Projekt unter Versionskontrolle hinzu. Wenn nicht, dann nichts tun. Und baue einfach die Bibliothek fertig.

Schritt 7

Schauen wir uns die Projektdateien an und ändern sie ein wenig.

Projektstruktur

QuiLib.pro

Diese Datei enthält die Information, dass es sich um eine Bibliothek handelt. Hier in dieser Zeile.

TEMPLATE = lib

Hier ist der vollständige Profilcode

#-------------------------------------------------
#
# Project created by QtCreator 2018-10-09T19:33:33
#
#-------------------------------------------------

QT       += widgets

TARGET = QuiLib
TEMPLATE = lib

DEFINES += QUILIB_LIBRARY

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        QuiLib.cpp

HEADERS += \
        QuiLib.h \
        quilib_global.h 

unix {
    target.path = /usr/lib
    INSTALLS += target
}

quilib_global.h

Header zum Definieren von Exportdefinitionen in der Bibliothek. Klassen, die mit einer Exportdefinition gekennzeichnet werden, stehen zur Verwendung außerhalb der Bibliothek zur Verfügung.

#ifndef QUILIB_GLOBAL_H
#define QUILIB_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(QUILIB_LIBRARY)
#  define QUILIBSHARED_EXPORT Q_DECL_EXPORT
#else
#  define QUILIBSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // QUILIB_GLOBAL_H

QuiLib.h

Lassen Sie uns die Header-Datei des Dialogfelds leicht korrigieren, da wir einen Dialog benötigen, was bedeutet, dass die Klasse in dieser Header-Datei von QDialog geerbt werden muss.

#ifndef QUILIB_H
#define QUILIB_H

#include "quilib_global.h"

#include <QDialog>

class QUILIBSHARED_EXPORT QuiLib : public QDialog
{

public:
    explicit QuiLib(QWidget* parent = nullptr);
};

#endif // QUILIB_H

QuiLib.cpp

Wir werden auch eine Implementierung des Dialogfeldkonstruktors schreiben, die uns mit QLabel mitteilt, dass dies ein Dialogfeld aus einer externen Bibliothek ist.

#include "QuiLib.h"

#include <QLabel>
#include <QGridLayout>


QuiLib::QuiLib(QWidget* parent) : QDialog(parent)
{
    QGridLayout* gridLayout = new QGridLayout(this);
    setLayout(gridLayout);
    gridLayout->addWidget(new QLabel("Hello world from dynamic library", this));
}

Schritt 8

Lassen Sie uns das Projekt in den Versionen Debug und Release kompilieren.

Hier ist beispielsweise, was sich im Release-Verzeichnis der Bibliotheksassembly befinden wird. Von diesen Dateien benötigen wir nur die Dateien QuiLib.dll und QuiLib.lib. Zusätzlich zu diesen Dateien benötigen wir auch Header-Dateien aus dem Projekt selbst, aber dazu später mehr.

Schritt 9

Erstellen eines Projekts, das diese dynamische Bibliothek verwendet. Der Erstellungsprozess erfolgt standardmäßig über einen Assistenten in Qt Creator. Sie müssen Application on Qt auswählen.

Fügen Sie den Projektnamen und den Standort hinzu

Schritt 10

Geben Sie einen Bausatz an.

Schritt 11

Lassen Sie uns den Namen der Klasse des Hauptfensters der Anwendung eingeben und auch angeben, von welcher Klasse geerbt werden soll. Ich habe mich für QWidget entschieden.

Schritt 12

Erneutes Auswählen eines Versionskontrollsystems und Abschluss des Projekterstellungsprozesses.

Schritt 13

Projektstruktur

Im Verzeichnis dieses Projekts erstellen wir ein Verzeichnis QuiLib , in dem wir die Verzeichnisse debug, release, include. ablegen.

Diese Verzeichnisse enthalten die kompilierten Bibliotheken QuiLib.dll und QuiLib.lib der Debug-Version bzw. der Release-Version. Das Include-Verzeichnis enthält die Header-Dateien QuiLib.h und quilib_global.h.

Das heißt, wir haben die Situation dargestellt, in der wir die kompilierte Bibliothek jemandem übergeben haben, damit er sie verbinden und verwenden kann.

Schritt 14

Hinzufügen der Bibliothek zum Projekt mithilfe des Assistenten. Natürlich können Sie alles manuell vorschreiben, aber wenn Sie an Ihren Fähigkeiten zweifeln, und das stimmt, sonst hätten Sie diesen Artikel nicht gelesen, dann verwenden wir einen Assistenten.

Schritt 15

Wir wissen, dass die Bibliothek extern ist

Schritt 16

Und auch, dass wir es nur für Windows verwenden werden. Es ist so konfiguriert, dass sich die Versionsdateien Debug und Release in unterschiedlichen Verzeichnissen ohne Debug-Bibliothekspräfixe befinden. Ich habe sie nur nicht eingerichtet. Es reicht aus, eine der .lib *-Bibliotheken entweder im Verzeichnis debug oder release anzugeben. Der Pfad zu einer anderen Version wird automatisch hinzugefügt. Sie müssen auch das Verzeichnis angeben, in dem sich die Header-Dateien befinden. Dies ist traditionell ein include**-Verzeichnis.

Schritt 17

Wir vervollständigen die Addition

Schritt 18

Sie müssen eine Methode schreiben, die ein Dialogfeld aus einer externen Bibliothek aufruft. Sehen Sie sich jedoch zuerst an, wo die Verbindungszeichenfolgen für Drittanbieterbibliotheken, die wir auf der Assistentenseite in Schritt 17. gesehen haben, hinzugefügt wurden.

Sehen wir uns nun das Profil unseres Projekts an, das die dynamische Bibliothek verwenden wird.

Mit DynamicLibrary.pro

#-------------------------------------------------
#
# Project created by QtCreator 2018-10-09T19:45:20
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = WithDynamicLibrary
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

CONFIG += c++11

SOURCES += \
        main.cpp \
        Widget.cpp

HEADERS += \
        Widget.h

FORMS += \
        Widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/QuiLib/release/ -lQuiLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/QuiLib/debug/ -lQuiLib

INCLUDEPATH += $$PWD/GuiLib/include
DEPENDPATH += $$PWD/GuiLib/include

Dies sind die allerletzten Zeilen in dieser Datei.

Widget.ui

Über den Grafikdesigner fügen wir dem Hauptfenster eine Schaltfläche hinzu, durch deren Drücken ein Dialog aus der externen Bibliothek aufgerufen wird.

Widget.h

Lassen Sie uns einen Slot schreiben, um den Klick auf die Schaltfläche zu verarbeiten.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void onPushButtonClicked(); // Слот для обработки клика по кнопке

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

Widget.cpp

Und jetzt verarbeiten wir den Schaltflächenklick und rufen das Dialogfeld aus der externen Bibliothek auf.

#include "Widget.h"
#include "ui_Widget.h"

#include <QPushButton>

// Подключаем заголовочный файл библиотеки
#include <QuiLib/include/QuiLib.h>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    // Подключаем слот к сигналу от кнопки
    connect(ui->pushButton, &QPushButton::clicked, this, &Widget::onPushButtonClicked);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::onPushButtonClicked()
{
    // Вызываем диалоговое окно
    QuiLib libWidget(this);
    libWidget.exec();
}

Beachten Sie, dass Sie das Dialogfeld mit der Methode exec() aufrufen müssen, um die interne Schleife des Dialogfelds zu starten, die auf Ereignisse wartet. Andernfalls wird der Dialog sofort geschlossen, da der Slot funktioniert und der Dialog in diesem Fall auf dem Methodenstapel erstellt wurde, und nach Abschluss der Methode wird der Dialog zerstört. Und die Methode exec() wird nur abgeschlossen, wenn das entsprechende Ereignis eintritt, wodurch der Dialog geschlossen wird.

Ergebnis

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

nayk1982
  • 9. Oktober 2018 21:49

Хороший урок, все подробно расписано. Такой вопрос: версия Qt для дин.библиотеки не обязательно должна совпадать с версией Qt проекта, который эту библиотеку использует?

Evgenii Legotckoi
  • 10. Oktober 2018 02:59

Спасибо ))

Из того, что я читал в документации, следует, что библиотеки Qt бинарно совместимы по минорным версиям. То есть, если проект работал с Qt 5.6, то можно поменять библиотеки на Qt 5.7 и по прежнему всё будет работать. На практике, конечно, не всегда всё гладко проходит. То есть по идее, если динамическая библиотека использует Qt 5.6, а подключили её в проект с Qt 5.7, то должно работать. Но опять же оговорюсь, на практике может выйти иначе, особенно, если динамическая библиотека использовала Qt 5.7, а подключили проект на Qt 5.6. Как минимум мождете оказаться, что в Qt 5.6 в каком-то классе отсутствуют некоторые методы.

То есть теоретически возможно, практически, как карта ляжет.



Docent
  • 10. Oktober 2018 04:21

Вот какой вопрос возник: для запуска программы вне Qt приходится тащить с ехе'шником кучу dll. А для использования созданной dll не придется ли тащить с собой всё те же Qt5Core.dll, Qt5Gui.dll, Qt5Widgets.dll...? Особенно если дальнейшее использование созданной dll планируется без участия Qt

Evgenii Legotckoi
  • 10. Oktober 2018 04:25

Погодите. Если речь идёт о библиотеке, которая использует Qt, от естественно, что ей понадобятся все те модули, от которых зависит бибилотека. Например в данном примере используются модули Qt5Core, Qt5Gui, Qt5Widgets, соответсвенно их тоже придётся тащить с собой. Если же вы создаёте библиотеку без участия Qt, то и модули Qt не будут нужны.

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

o
  • 10. Oktober 2018 04:28

Круто было бы прочитать про приложение с подключаемыми плагинами.

Evgenii Legotckoi
  • 10. Oktober 2018 04:31

Типо как в Qt Creator?

Самому бы интересно было о таком почитать. В данный момент я бы мог написать только о написании плагинов для Qt Designer. С этим есть некоторый опыт.

o
  • 10. Oktober 2018 05:46

ну типа того, создание программы, функционал которой можно расширять плагинами, и, в перспективе, создание API.

o
  • 10. Oktober 2018 05:48

О плагинах к QtCreator в целом, тоже интересно.

Evgenii Legotckoi
  • 10. Oktober 2018 05:50

Если и начинать писать о плагинах, то нужно тогда с Qt Creator начинать, там наверняка будет одинаковый принцип, но по Qt Creator хотя бы информация есть.

o
  • 10. Oktober 2018 09:16

наверняка, так и есть)

B
  • 20. Oktober 2018 12:51

В принципе у меня есть опыт реализации плагинов, могу что-нибудь накропать как будет время

Evgenii Legotckoi
  • 21. Oktober 2018 11:10

Это было бы здорово и полезно ))

При запуске приложения библиотека должна лежать рядом с исполняемым файлом. А как сделать так, чтобы библиотека лежала в папке на уровень ниже чем сам исполняемый файл?

nayk1982
  • 8. Januar 2019 21:02

QApplication::addLibraryPath()

Можно в каталоге приложения создать файл qt.conf в котором прописать пути библиотек:

[Paths]
Libraries=./lib
Plugins=./lib

Edward Wayne
  • 4. März 2019 02:17

А можно динамическую библиотеку, скомпелированную в Visual Studio и никак не связанную с Qt, подключить в проект который разрабатывается в Qt?

Какие действия для этого нужно сделать?

Достаточно ли будет просто заменить эти строки:

#if defined(QUILIB_LIBRARY)
#  define QUILIBSHARED_EXPORT Q_DECL_EXPORT
#else
#  define QUILIBSHARED_EXPORT Q_DECL_IMPORT
#endif

на эти:

#define QUILIB_EXPORT __declspec(dllexport)

?

Evgenii Legotckoi
  • 4. März 2019 04:22

Полагаю, что да, нужно переписать экспорт, как вы написали. А подключение в Qt проекте будет аналогичным, такженаличие пути к библиотеке и заголовочные файлы. Главное, чтобы компиляторы были одной версии.

e
  • 16. November 2020 04:32

здравствуйте! при компиляции библиотеки выскакивает окно особая программа( не удалось найти программу, укажите путь к ней), и в папке debug создается файл .dll, а .lib нет. подскажите, пожалуйста, в чем проблема.

DS
  • 16. Februar 2022 06:54

Добрый день!
Очень мало информации, как писать классы с методами для компиляции в динамическую библиотеку.
Пример: в классе QuiLib дополнительно есть методы, которые могут вызываться, например

void setText(QString t) {
qlabel->setText(t);
}

то этот метод следует обьявлять как virtual, чтобы потом вызвать его где надо, верно?

Evgenii Legotckoi
  • 17. Februar 2022 03:51

Нет, не верно. Модификатор virtual помечает метод класса как виртуальный, что позволяет переопределять методы при наследовании классов. К библиотекам вообще никакого отношения не имеет.

Обычно функции отдельно помечаются макросом типо QUILIBSHARED_EXPORT, но проще написать класс helper со статическими методами, ибо потом меньше проблем с линковкой и компиляцией.

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken