Wie eine Shared Library mit Qt richtig erstellen?

Alles rund um die Programmierung mit Qt
Antworten
Vaughn
Beiträge: 6
Registriert: 26. November 2008 08:16

Wie eine Shared Library mit Qt richtig erstellen?

Beitrag von Vaughn »

Ich würde gerne mit Qt eine Shared Library (dll) erstellen, bin dabei allerdings auf arge Probleme gestoßen.

Um es besser zu verstehen habe ich zwei einfache Test-Projekte angelegt.

Als erstes soll die lib erstellt werden:

qtseclib.h:

Code: Alles auswählen

#ifndef QTSECLIB_H
#define QTSECLIB_H

#include <QtGui>

class QtSecLib : public QWidget
{
    Q_OBJECT

public:
    QtSecLib(QWidget *parent = 0);
    ~QtSecLib();
};

#endif // QTSECLIB_H
in der entsprechenden qtseclib.cpp stehen nur die fast leeren (De)Konstrutoren

die .pro dazu:

Code: Alles auswählen

TEMPLATE = lib
TARGET = QtSecLib
QT += core \
    gui 
HEADERS += qtseclib.h
SOURCES += main.cpp \
    qtseclib.cpp
FORMS += 
RESOURCES += 
FORMS += 

Diese Klasse QtSecLib soll nun in einer App vererbt werden:
qtestapp.h:

Code: Alles auswählen

#ifndef QTESTAPP_H
#define QTESTAPP_H

#include <QtGui>
#include "qtseclib.h"

class QTestApp : public QtSecLib
{
    Q_OBJECT
public:
    QTestApp(QWidget *parent = 0);
    ~QTestApp();
};

#endif // QTESTAPP_H
Die qtestapp.cpp dazu ist auch wieder fast leer:

Code: Alles auswählen

#include "qtestapp.h"

QTestApp::QTestApp(QWidget *parent) : QtSecLib(parent)
{
	QMessageBox::information(this,"Info","QTestApp Construction");
}

QTestApp::~QTestApp()
{
	QMessageBox::information(this,"Info","QTestApp Deconstruction");
}
und die .pro:

Code: Alles auswählen

TEMPLATE = app
TARGET = QTestApp
QT += core \
    gui
HEADERS += qtestapp.h
SOURCES += main.cpp \
    qtestapp.cpp
FORMS += 
RESOURCES += 
INCLUDEPATH += c:\workspace\QtSecLib
LIBS += c:\workspace\QtSecLib\debug\QtSecLib.dll
Während unter Ubuntu soweit alles hervorragend funktioniert (natürlich angepasste .pro files) klappt dies unter Windows überhaupt nicht.
Es kommt nur:
Die Anwendung konnte nicht richtig initialisiert werden (0xc0000005). ...
Jetzt noch das witzigste:
Wenn ich die Makros Q_OBJECT entferne und übersetze und laufen lasse ist alles bestens. Programm tut was es soll.
Wenn ich die Makros wieder einfüge und übersetze läuft es immernoch!!!!
Wenn ich dann allerdings ein make clean und dann wieder übersetze geht es wieder nicht mehr. Das soll mal einer verstehen.... Ich jedenfalls nicht...

Also ich habe natürlich viel gesucht und gefunden das man für eine dll noch dies tun sollte:

Code: Alles auswählen

#ifdef BUILD_LIB
#define EXPORT_LIB Q_DECL_EXPORT
#else
#define EXPORT_LIB
#endif

class EXPORT_LIB QtSecLib : public QWidget
Ich weiß leider nicht warum oder wie es richtig aussehen sollte, denn leider hat dieser ansatz auch nicht funktioniert....


Also meine Bitte:
Könnte mir jemand erklären wie man mit Qt unter Windoof eine dll (inkl Q_OBJECT) erstellt?


Ich verwende die frisch installierte qt-win-opensource-4.4.3-mingw unter eclipse und mit der Qt Eclipse Integration.

vielen Dank für die Mühe
Vaughn
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

ja.. DAS hat mich auch schon viiieeel Zeit gekostet...

Folgendes Vorgehen:

1. Erstelle in deiner Library eine Include-Datei "global.h mit folgendem Inhalt:

Code: Alles auswählen

#ifndef  _MEINE_LIB_GLOBAL_HEADER_
#define  _MEINE_LIB_GLOBAL_HEADER_

#    if defined(BUILD_MEINE_LIB)
#      define MEINE_LIB_EXPORT Q_DECL_EXPORT
#    else 
#      define MEINE_LIB_EXPORT Q_DECL_IMPORT
#    endif

#endi
2. includiere diese in allen zu exportierenden Klassenheaders und fuege den Export-String vor dem Klassennamen ein:

Code: Alles auswählen

// file myclass.h
#include "global.h"
class MEINE_LIB_EXPORT myclass: public QWidget
{
  ....
};
3. in der pro-Datei der Library (und NUR in dieser!!)

Code: Alles auswählen

DEFINES += BUILD_MEINE_LIB
das ganze bewirkt, dass Qt unter Windows automatisch den richtigen "_declexport" vor den Klassennamen einfügt.. und Linux wird IMHO gar nichts gemacht..

hth

PS.
Ich glaube nicht, dass die Source-Datei "main.cpp" in der Pro-File deiner Library was zu suchen hat... oder?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

solarix hat geschrieben: und Linux wird IMHO gar nichts gemacht..
Falsch :)
Ab gcc 4.1 schon --> siehe gcc Option --fvisibility und --fvisibility-inline-hidden
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Vaughn
Beiträge: 6
Registriert: 26. November 2008 08:16

Beitrag von Vaughn »

Danke für die Antwort, werd es gleich mal ausprobieren und berichten.

Was ich allerdings schon einige male getestet hatte war folgendes:

Code: Alles auswählen

class Q_DECL_EXPORT QtSecLib : public QWidget 
Wenn ich es richtig verstehe macht dein Makro dann auch nicht viel anderes. Das obige hat allerdings leider nicht geholfen...

Ich werde es aber gleich mal testen...
PS.
Ich glaube nicht, dass die Source-Datei "main.cpp" in der Pro-File deiner Library was zu suchen hat... oder?
Ja die main.cpp in der lib ist unsinn und noch ein unbeabsichtigtes Überbleibsel als ich die lib als eigene APP mal getestet hatte.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Vaughn hat geschrieben: Wenn ich es richtig verstehe macht dein Makro dann auch nicht viel anderes.
Doch - es macht sehr viel anders. Nämlich im Falle des Linkens gegen die Library!
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Vaughn
Beiträge: 6
Registriert: 26. November 2008 08:16

Beitrag von Vaughn »

Wie ich befürchtet hatte... es hat nicht geholfen....

Code: Alles auswählen

#ifndef QTSECLIB_H
#define QTSECLIB_H

#include <QtGui>
#ifdef BUILD_LIB
#define EXPORT_LIB Q_DECL_EXPORT
#else
#define EXPORT_LIB
#endif

class EXPORT_LIB QtSecLib : public QWidget
{
    Q_OBJECT

public:
    QtSecLib(QWidget *parent = 0);
    ~QtSecLib();
};

#endif // QTSECLIB_H
Ich hab es jetzt für die eine Klasse noch nicht in eine eigene global.h erstellt, würde ich dann später natürlich tun, aber daran sollte es hier ja wohl nicht liegen denke ich.

Also ich bin etwas ratlos....

Interessant ist auch, wenn ich die App-Klasse nicht von der Lib-Klasse ableite sondern von QWidget und die Lib-Klasse nur im APP erzeuge ist auch alles gut.
qtestapp.cpp:

Code: Alles auswählen

#include "qtestapp.h"

QTestApp::QTestApp(QWidget *parent) : QWidget(parent)
{
	QMessageBox::information(this,"Info","QTestApp Construction");

	QtSecLib * test = new QtSecLib();
}

QTestApp::~QTestApp()
{
	QMessageBox::information(this,"Info","QTestApp Deconstruction");
}
Jemand eine Idee was hier schief läuft??
Und warum klappt es ohne das Q_OBJECT makro??
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Christian81 hat geschrieben: Ab gcc 4.1 schon --> siehe gcc Option --fvisibility und --fvisibility-inline-hidden
spannend :wink: , thx..
Wenn ich es richtig verstehe macht dein Makro dann auch nicht viel anderes.
es macht nicht _viel_ anderes.. aber der kleine Unterschied machts genau aus :wink:

[EDIT]
Hast du das "DEFINE" ebenfalls in die Pro-Datei eingefuegt und mal kräftig beide Projekte mit "make distclean; qmake; make" neu generiert?
Vaughn
Beiträge: 6
Registriert: 26. November 2008 08:16

Beitrag von Vaughn »

So hab jetzt nochmal alles umgesetzt was Vorgeschlagen wurde:

Eigene QtSecLibGlobal.h:

Code: Alles auswählen

#ifndef QTSECLIBGLOBAL_H_
#define QTSECLIBGLOBAL_H_

#ifdef BUILD_LIB
#define EXPORT_LIB Q_DECL_EXPORT
#else
#define EXPORT_LIB
#endif

#endif /* QTSECLIBGLOBAL_H_ */
die .pro

Code: Alles auswählen

TEMPLATE = lib
TARGET = QtSecLib
QT += core \
    gui
HEADERS += QtSecLibGlobal.h \
    qtseclib.h
SOURCES += qtseclib.cpp
FORMS += 
RESOURCES += 
FORMS += 
DEFINES += BUILD_LIB
und "make distclean; qmake; make" in der Reihenfolge ausgeführt...

so sieht die QTestApp.pro jetzt aus:

Code: Alles auswählen

TEMPLATE = app
TARGET = QTestApp
QT += core \
    gui
HEADERS += qtestapp.h
SOURCES += main.cpp \
    qtestapp.cpp
FORMS += 
RESOURCES += 
INCLUDEPATH += c:\workspace\QtSecLib
LIBS += -Lc:\workspace\QtSecLib\debug\ \
    -lQtSecLib
Leider noch kein Erfolg :(
Vaughn
Beiträge: 6
Registriert: 26. November 2008 08:16

Fehler gefunden!

Beitrag von Vaughn »

Scheinbar hab ich den Fehler gefunden!

das stand in meiner global.h

Code: Alles auswählen

#ifdef BUILD_LIB
#define EXPORT_LIB Q_DECL_EXPORT
#else
#define EXPORT_LIB
#endif 
und das hätte stehen müssen (so wie es solarix auch geschrieben hat):

Code: Alles auswählen

#ifdef BUILD_LIB
#define EXPORT_LIB Q_DECL_EXPORT
#else
#define EXPORT_LIB Q_DECL_IMPORT
#endif 
Also wie immer ein blöder Fehler.... :roll:

Nungut, das mit dem Q_DECL_EXPORT/IMPORT war mir auch neu.

Steht das eigentlich nirgends mal Dokumentiert von Trolltech? Das mit dem Q_OBJECT usw. wird ja auch erklärt....

Danke nochmal für die geduldigen Antworten....
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Warum sollte Trolltech das erklären wo es doch ein generisches C/C++ Windows-Problem ist?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Vaughn
Beiträge: 6
Registriert: 26. November 2008 08:16

Beitrag von Vaughn »

Naja die Makros Q_DECL_EXPORT/IMPORT sind ja wohl Qt spezifisch oder nicht?

Mir ist dieses Problem bei dll's jedenfalls komplett neu. Wo kann man darüber mal was nachlesen?

Wie sieht das also bei einer "normalen" c++ classen lib aus?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Q_DECL_EXPORT/IMPORT sind nur macros für __declspec(dllexport) und __declspec(dllimport) und nichts weiter. In der msdn ist das alles beschrieben, außerdem sollte google auch hier helfen. Qt ist 'normales' C++ - also gibts auch keine Unterschiede.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Antworten