[gelöst] QLibrary / DLL in Klasse (Warning Multiple Declare)

Du bist neu in der Welt von C++? Dann schau hier herein!
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

Jop, ich kenne den Programmierer und habe mir nun den Quelltext besorgt .. sprich ich schreib mir nun selbst die DLL die ich brauche.

Nur fange ich da bei NULL an .. habe nie was mit DLLs am Hut gehabt, deshalb auch meine ganze Fragerei, die mich mitlerweile selber nervt. ;)

Steh da gerade vor der QT Hürde. Habe über Neu->C++ Bibliothek mir ein neues Projekt gemacht, welches ich im leeren Zustand kompilieren will, um zu gucken ob er mir am Ende auch eine *.dll ausgibt.
Es erscheint im Creator die Meldung: "Es konnte keine ausführbare Datei gefunden werden; bitte geben Sie eine an. Es wurde keine ausführbare Datei angegeben. [Details anzeigen]"
Unter Details sind Name, Ausführbare Datei und Argumente leer, außer Arbeitsverzeichnis.

Was möchte QT mir damit sagen? Welche ausführbare Datei denn?

[NACHTRAG:] Was ich durch Google in Erfahrung bringen konnte ist, das die Usprungsnachricht (eng.) wahrscheinlich anders lautet. Anscheinend braucht es kein qmake sondern cmake für den Build-Prozess und noch ein paar Parameter im Build-Schritt.
Wenn dem so sein sollte frag ich mich ernsthaft, warum das nicht bei Erstellen des Projektes mitkonfiguriert worden ist. :evil:
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Aehm , wer sagt dir was ? ^^

du verwendest mingw/gcc ok, damit wissen wir den compiler.
compiler koennen aber nix mit projecten.
Dafuer iss die IDE und / oder das maketool zustaendig

Ich vermut du benutzt den qt-Creator oder ?
der wird aber qmake und nich cmake verwenden ....

Die meisten IDE's haben ein propertiaeres projectformat und koennen makefiles (make, qmake,cmake ... ) exportieren manchmal sogar importieren.

QT sollte eigentlich nur ueber die runtime Debug mit dir "reden" ^^ iss ja eigentlich nur ne Lib. Ansonsten redet mit dir die IDE (QT-Creator vielleicht), der compiler/linker (gcc in deinem fall) oder das maketool(qmake wahrscheinlich).
"Es konnte keine ausführbare Datei gefunden werden;
deutet IMHO darauf hin das du project kompilieren und starten getriggert hasst. kompilieren kann er dlls, starten aber ned ^^ dazu muss man nen executable einstellen, welches stattdessen gestartet wird und deine dll anzieht. Das hasst wahrscheinlich noch ned gemacht :-)

Ciao ...
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

Alles klar, ich sollte nun wohl mal eine Pause einlegen. RHBaum, du hast recht, habe im Creator auf Ausführen geklickt und nicht auf Erstellen. :oops:
Den Rest versuche ich mir dann aus dem Forum zusammen zu suchen, gibt ja einige Threads über DLL erstellen/einbinden etc.
Hier, hier, und hier ..

Bei Fragen melde ich mich nochmal, danke an alle für die weitreichende Hilfe bis hierhin.
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

Ich habe jetzt nochmal seeehr viel rumprobiert und bin zu keinerlei Ergebnis gekommen, beim Erstellen von Shared Libs für mein QT Programm.

Nach etlichen Foreneinträgen habe ich mir mitlerweile die 3. Pro-Datei für die DLL gebaut und es funktioniert immernoch nicht. In der QT Doku zu Shared Libs steht; man bräuchte eine [Projektname]_global.h ?!

Kann mal jemand an dem folgenden Projekt zeigen was ihm auffällt, warum das Projekt nicht funktioniert?

PS: Es ist mir egal ob statisches oder dynamisches Linken, der Unterschied wird mir auch durch die Wiki-Artikel nicht deutlich. -.-

Die Ausgabe ist stehts: "Die Funktion hallo_dll konnte nicht geladen werden!
Cannot resolve "hallo_dll" in lool: Die angegebene Prozedur wurde nicht gefunden!"

*.pro-File der DLL (testDll.pro)

Code: Alles auswählen

-------------1.Versuch-------------
TARGET = lool
TEMPLATE = lib
HEADERS += lool.h
SOURCES += lool.cpp
-------------2.Versuch-------------
TARGET = lool
TEMPLATE = lib
HEADERS += lool.h\
        lool_global.h
SOURCES += lool.cpp
DEFINES += LOOL_LIBRARY
-------------3.Versuch-------------
TARGET = lool
TEMPLATE = lib
HEADERS += lool.h\
        lool_global.h
SOURCES += lool.cpp
DEFINES += LOOL_LIBRARY
CONFIG += staticlib
*.h-File der DLL (lool.h)

Code: Alles auswählen

-------------1.Versuch-------------
#ifndef LOOL_H
#define LOOL_H

#include <QtCore/qglobal.h>

#if defined(LOOL_LIBRARY)
#  define LOOLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define LOOLSHARED_EXPORT Q_DECL_IMPORT
#endif

void Q_DECL_EXPORT hallo_dll(); 

#endif // LOOL_H
-------2.Versuch-------------
#ifndef LOOL_H
#define LOOL_H

#include <QtCore/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 
#  ifdef Q_OS_WIN 
#    define Q_DECL_IMPORT __declspec(dllimport) 
#  else 
#    define Q_DECL_IMPORT 
#  endif 
#endif

void Q_DECL_EXPORT hallo_dll(); 

#endif // LOOL_H
*.cpp-File der DLL (lool.cpp)

Code: Alles auswählen

#include "lool.h"
#include <QMessageBox>

void hallo_dll()
{
    QMessageBox msgBox;
    msgBox.setText("The document has been modified: Alone");
    msgBox.exec();
}
*.pro-File meines Programms (myDllTest.pro)

Code: Alles auswählen

LIBS += "lool.dll"
HEADERS = mainwindow.h
SOURCES = mainwindow.cpp \
    main.cpp
*.h-File meines Programms (mainwindow.h)

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QWidget>
#include <QtGui>

class DLLFNC
{
private:
    typedef void (*CBhallo_dll)();
public:
    DLLFNC();
    CBhallo_dll myhallo_dll;
};

class MainWindow : public QWidget{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    DLLFNC *myDLLFNC;
};
#endif
*.cpp-File meines Programms (mainwindow.cpp)

Code: Alles auswählen

#include "mainwindow.h"

DLLFNC::DLLFNC()
{
    QMessageBox msgBox;
    QFile file("lool.dll");
    if(file.exists()==true){
        QLibrary myLib("lool");
        if(myLib.isLibrary("lool.dll")==true){
            if(myLib.load()==true){
                if(myLib.isLoaded()==true){
                    myhallo_dll = (CBhallo_dll) myLib.resolve("hallo_dll");
                    if (myhallo_dll){
                        msgBox.setText("Die Funktion hallo_dll wurde erfolgreich geladen!\n");
                        msgBox.exec();
                    }else{
                        msgBox.setText("Die Funktion hallo_dll konnte nicht geladen werden!\n"+myLib.errorString());
                        msgBox.exec();
                    }
                }else{
                    msgBox.setText("Die DLL lool wurde nicht geladen!\n"+myLib.errorString());
                    msgBox.exec();
                }
            }else{
                msgBox.setText("Die DLL lool konnte nicht geladen werden!\n"+myLib.errorString());
                msgBox.exec();
            }
        }else{
            msgBox.setText("Die DLL lool ist keine Bibliothek\n"+myLib.errorString());
            msgBox.exec();
        }
    }else{
        msgBox.setText("Die DLL lool .dll existiert nicht an dem angegebenen Ort!");
        msgBox.exec();
    }
}

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    myDLLFNC= new DLLFNC();
    myDLLFNC->hallo_dll();
}
*.cpp-File des Programms (main.cpp)

Code: Alles auswählen

#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
}
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Deine Funktion muss in der Dll selber mit

Code: Alles auswählen

void Q_DECL_EXPORT hallo_dll(); 
exportiert werden,
in der exe aber mit

Code: Alles auswählen

void Q_DECL_IMPORT hallo_dll(); 
Genau dafuer gibt es aber das define mit der Praeprozessordirektive:

Code: Alles auswählen

#ifdef(LOOL_LIBRARY)
#define LOOLSHARED_EXPORT Q_DECL_EXPORT
#else
#define LOOLSHARED_EXPORT Q_DECL_IMPORT
#endif 

void LOOLSHARED_EXPORT hallo_dll(); 
muesste deine header datei aussehen.

und wichtig, bei dem dll project muss dann das LOOL_LIBRARY für den Praeprozessor definiert sein.
bin mir ned sicher ob Q_DECL_EXPORT schon den eintrag in der exportliste erzeugt. Schon mal mit einer .def Datei probiert ?

Ciao ....
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

@ RHBaum: Wenn ich deinen Header für die Library verwende kommt folgendes dabei rum:
?: In file included from lool.cpp:1:
error: macro names must be identifiers
warning: 'void hallo_dll()' redeclared without dllimport attribute: previous dllimport ignored
Nein, bei dem Versuch habe ich keine *.def bislang benutzt .. ich weiß ich auch nicht warum ihr immer nach einer *.def fragt.

PS: Habe die *.def gerade mal wieder auf umwegen erzeugt und siehe da, ist ja doch für was gut das Teil: Die Kompilierung zerschießt den Funktionsnamen, deswegen kann auch nicht resolved werden, würde ich nun mal behaupten:

lool.def

Code: Alles auswählen

LIBRARY lool.dll
EXPORTS
_Z9hallo_dllv
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ich kapiere nicht warum das ganze jetzt immer noch zur Laufzeit geladen werden muss... einfach dynamisch linken und gut ist. Wenn die DLLexport korrekt nach RHBaums vorgaben gemacht worden sind wird neben der DLL auch noch eine .a erzeugt. Gegen die linkt man dann und fertig.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

Also wie gesagt, wenn ich den Header von RHBaum übernehme habe ich Compiler-Probleme (s.o.)

Von daher ist nichts mit Vorgaben übernehmen ...

Weiterhin sollte es zur Laufzeit geladen werden, weil die Library austauschbar sein muss und dafür will ich den Benutzer nicht dauernd das Programm neustarten lassen.

Letztlich muss mir dann auch mal jemand sagen, das nicht gegen die *.dll geschossen wird sondern gegen die *.a

Warum überhaupt?

PS: Habe es jetzt hinbekommen, das er die DLL lädt und auch dessen Funktionen .. nachdem die *.def angezeigt hat, dass das Funktionsname zerschossen ist, habe ich eben diesen Namen für den resolve-Befehl bei QLibrary verwendet und siehe da - es funktioniert.

Wenn mich jetzt noch jemand informieren würde, warum der Funktionsname zerschossen wird, wäre ich noch glücklicher. :)
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Wenn mich jetzt noch jemand informieren würde, warum der Funktionsname zerschossen wird, wäre ich noch glücklicher.
du uebersetzt mit nem C++ compiler (gcc). der betreibt massivst name mergling.

dein QLibrary geht aber wahrscheinlich davon aus, dass den FUnktionsnamen ungemergelt uebergibst (getProcAdress).

Klar das das ned hinhaut ... haett ich auch drauf kommen muessen.

Um namemergling auszuschalten:
- def dateien

oder

Code: Alles auswählen

#ifdef(LOOL_LIBRARY)
#define LOOLSHARED_EXPORT Q_DECL_EXPORT
#else
#define LOOLSHARED_EXPORT Q_DECL_IMPORT
#endif

#ifdef __cplusplus 
extern c 
{
#endif

void LOOLSHARED_EXPORT hallo_dll(); 

#ifdef __cplusplus 
}
#endif
Habe die *.def gerade mal wieder auf umwegen erzeugt
Wieso lässt man die def Datei erzeugen ?
Der vorteil ist doch:
- das man namemergling umgeht
- man eigentlich generell die FUnktionsnamen noch mal umdefinieren kann
- man auch indizierten zugriff bieten kann (schneller, da kein stringvergleich im getProcAdress)

Schreib die doch per hand !

lool.def

Code: Alles auswählen

LIBRARY lool.dll
EXPORTS
hallo_dll=_Z9hallo_dllv 
würde z.b. das namemergling rückgängig machen


uebrigens um sich unter windows die exporttabelle einer Dll anzuschauen und besonders die funktionsnamen in C-Form(so wie sie getProcAdress braucht), eignet sich der Dependency walker super (wird mit VC mitgeliefert).
http://www.dependencywalker.com/

Ciao ...
Zuletzt geändert von RHBaum am 7. Juni 2010 14:57, insgesamt 2-mal geändert.
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

RHBaum, teilweise verstehe ich deine Posts einfach nicht.

Du meinst also ich sollte entweder die Header der DLL anpassen, dass das Namemergling aufhört oder ich mach es mir noch einfacher und erstelle eine *.def-Datei.

Wie erstellen? Mit Compiler-Parametern? Per Hand? Per Tool?
Und danach? In QLibrary die *.def-Datei angeben? Per Include einbinden? Per *.pro-Datei? (wären schon neun Möglichkeiten) :?

Es gibt so abartig viele Wege wie man deine Beschreibung durchführen könnte, nur will ich gewiss nicht alle Wege durchprobieren. :)

PS: Wenn du meinen Post gelesen habe solltest(Siehe Oben), solltest du gesehen haben, dass dein Code-Block für die Header in der DLL Probleme macht.....
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

ok, mein konkreter Vorschlag:

- Def Datei erst mal weglassen, in dem du die ausm project eliminierst
- name Mergling ausschalten, in dem du in dem header, in dem deine Exportanweisung generiert wird, also dein lool.h folgendermassen modifizierst:

Code: Alles auswählen

#ifdef LOOL_LIBRARY /// warum eigentlich die Klammern ??? 
#define LOOLSHARED_EXPORT Q_DECL_EXPORT
#else
#define LOOLSHARED_EXPORT Q_DECL_IMPORT
#endif

#ifdef __cplusplus
extern c
{
#endif

void LOOLSHARED_EXPORT hallo_dll();

#ifdef __cplusplus
}
#endif
Laesst sich das compilieren, wenn nein, Fehlermeldung ?

wenn compilieren erfolgreich:
- nachschauen ob das namemergling auch wirklich aus ist ! Dependency walker besorgen, deine Dll damit öffnen, sich den Namen der exportierten funktion (sollte nur eine geben) anschauen !
Wenn die hallo_dll lautet, ohne irgendwelche kryptischen _@z37_v zeichen davor oder danach -> laut vor freude aufschreien !

Ciao ...
Zuletzt geändert von RHBaum am 7. Juni 2010 15:12, insgesamt 1-mal geändert.
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

Nein, lässt sich leider nicht kompilieren ..
C:/QtProjekte/lool/lool.cpp:1: In file included from lool.cpp:1:
C:/QtProjekte/lool/lool.h:6: error: macro names must be identifiers
C:/QtProjekte/lool/lool.cpp:1: In file included from lool.cpp:1:
C:/QtProjekte/lool/lool.h:13: error: ISO C++ forbids declaration of 'c' with no type
C:/QtProjekte/lool/lool.h:13: warning: 'c' initialized and declared 'extern'
C:/QtProjekte/lool/lool.h:13: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x
C:/QtProjekte/lool/lool.h:17: error: expected primary-expression before 'void'
C:/QtProjekte/lool/lool.h:17: error: expected '}' before 'void'
C:/QtProjekte/lool/lool.h:17: error: expected ',' or ';' before 'void'
C:/QtProjekte/lool/lool.h:20: error: expected declaration before '}' token
<lool.h>

Code: Alles auswählen

01: #ifndef LOOL_H
02: #define LOOL_H
03: 
04: #include <QtCore/qglobal.h>
05: 
06: #ifdef(LOOL_LIBRARY)
07: #define LOOLSHARED_EXPORT Q_DECL_EXPORT
08: #else
09: #define LOOLSHARED_EXPORT Q_DECL_IMPORT
10: #endif
11: 
12: #ifdef __cplusplus
13: extern c
14: {
15: #endif
16: 
17: void LOOLSHARED_EXPORT hallo_dll();
18: 
19: #ifdef __cplusplus
20: }
21: #endif
22:
23: #endif // LOOL_H
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Mein fehler:
#ifdef(LOOL_LIBRARY) <- Klammern weg
also:
#ifdef LOOL_LIBRARY
Pixtar
Beiträge: 97
Registriert: 5. Mai 2010 15:32

Beitrag von Pixtar »

Nein, nur ein wenig verbessert, es bleiben:
C:/QtProjekte/lool/lool.cpp:1: In file included from lool.cpp:1:
C:/QtProjekte/lool/lool.h:13: error: ISO C++ forbids declaration of 'c' with no type
C:/QtProjekte/lool/lool.h:13: warning: 'c' initialized and declared 'extern'
C:/QtProjekte/lool/lool.h:13: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x
C:/QtProjekte/lool/lool.h:17: error: expected primary-expression before 'void'
C:/QtProjekte/lool/lool.h:17: error: expected '}' before 'void'
C:/QtProjekte/lool/lool.h:17: error: expected ',' or ';' before 'void'
C:/QtProjekte/lool/lool.h:20: error: expected declaration before '}' token
Wenn ich Zeile 13 abänder in:

Code: Alles auswählen

extern c void
und bei Zeile 17 das void der Funktion weglasse:
C:/QtProjekte/lool/lool.cpp:1: In file included from lool.cpp:1:
C:/QtProjekte/lool/lool.h:13: error: expected initializer before 'void'
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Du brauchst weder die .h noch die ganzen äifdef und ädefines! Du willst eine Library, die nur dynamisch zur Laufzeit geladen werden kann!
Da reicht folgendes simples cpp-file:

Code: Alles auswählen

#include <QtCore/QtGlobal>
#include <iostream>

extern "C" {
    void Q_DECL_EXPORT call() {
        std::cout << "Hallo" << std::endl;
    }
}
Das Kompilieren und als shared-lib linken - fertig.
Hab das hier sogar extra ausprobiert (Linux) und es funktioniert. Leider hab ich kein Windows, aber ich nehme an, auch dort gibt es keine Probleme.
Antworten