[gelöst für Plugins] DLLs sollen in ein Unterverzeichnis
[gelöst für Plugins] DLLs sollen in ein Unterverzeichnis
Ich möchte diverse externe von meinem Programm benötigte Bibliotheken in einem Unterverzeichnis "bin" verstauen.
Der Normalfall ist, dass Qt-Bibliotheken im Programmverzeichnis liegen müssen, Qt-Plugin-Bibliotheken in einem Unterverzeichnis mit Namen des Plugins usw., das ist mir zu dumm. Daher möchte ich entweder diese Unterverzeichnisse wegrationalisieren oder am besten alles in einem gemeinsamen Unterordner "bin" liegen haben, auch nicht-Qt-libs.
Würde gern wissen wie das geht, ich hoffe es reicht, irgendwelche Angaben in der .pro-Datei zu ändern, z.B. Suchpfade zu setzen o.ä., in der Doku hab ich nichts gefunden.
MfG,
FaS
Der Normalfall ist, dass Qt-Bibliotheken im Programmverzeichnis liegen müssen, Qt-Plugin-Bibliotheken in einem Unterverzeichnis mit Namen des Plugins usw., das ist mir zu dumm. Daher möchte ich entweder diese Unterverzeichnisse wegrationalisieren oder am besten alles in einem gemeinsamen Unterordner "bin" liegen haben, auch nicht-Qt-libs.
Würde gern wissen wie das geht, ich hoffe es reicht, irgendwelche Angaben in der .pro-Datei zu ändern, z.B. Suchpfade zu setzen o.ä., in der Doku hab ich nichts gefunden.
MfG,
FaS
Zuletzt geändert von FaS am 19. August 2007 16:38, insgesamt 1-mal geändert.
Also spontan fallen mir da 3 möglichkeiten ein:
1. die unsaubere aber einfache lösung
dein bin verzeichnis in die PATH umgebungsvariable unter windows (entsprechendes für die anderen OS) eintragen. Dann sucht das Betriebssystem beim startet deines Programms in diesem (und anderen) ordnern nach den libraries und wird fündig.
2. die sauberere aber kompliziertere lösung
du musst die libraries und die benötigten funktionen per hand laden.
3. die wohl sauberste und auch einfachste lösung
dein programm direkt mit in den bin ordner packen und dann beim starten das arbeitsverzeichnis auf ../ ändern.
1. die unsaubere aber einfache lösung
dein bin verzeichnis in die PATH umgebungsvariable unter windows (entsprechendes für die anderen OS) eintragen. Dann sucht das Betriebssystem beim startet deines Programms in diesem (und anderen) ordnern nach den libraries und wird fündig.
2. die sauberere aber kompliziertere lösung
du musst die libraries und die benötigten funktionen per hand laden.
3. die wohl sauberste und auch einfachste lösung
dein programm direkt mit in den bin ordner packen und dann beim starten das arbeitsverzeichnis auf ../ ändern.
If you smile and no one else is around, you really mean it
Danke Dawn für deine Tipps, ich würde das Problem aber jetzt gerne von der Ursache her betrachten. Zunächst mal deine Vorschläge:
1. PATH - ist wirklich nicht sehr schön und verlangt eine Installation.
2. Funktionen manuell laden - wenn das so aufwendig ist wie es sich anhört..
3. Programm im bin-Ordner - ich würde es schon gerne im Stammordner haben, wie soll es der Benutzer sonst ausführen. Eine Verknüpfung im Programmordner ist unschön und würde den Speicherort des Programms bindend machen.
Also, wo steht geschrieben, dass z.B. Qt-Plugin-DLLs in einem Unterordner mit dem Namen des Plugins liegen müssen, das wird doch sicherlich beim linken in die Anwendung gemeißelt, kann man das nicht ändern? Im erzeugten makefile konnte ich diesbezüglich nichts direkt finden..
Speziell geht es mir um die QCA-(Crypto-)API, seine DLL akzeptiert der im Programmordner, aber einige Funktionen werden als Plugins zur Verfügung gestellt und liegen in <Qt-Dir>/plugins/crypto, ich fürchte dass die Haupt-Bibliothek explizit dort nach ihnen sucht, also in einem Unterordner namens crypto - mann was haben die sich nur dabei gedacht, ist doch krank: die Haupt-DLL ist ja auch nicht in diesem Ordner.. Wenn dies der Fall sein sollte gibts wohl keine Lösung? Was nimmt er als Ausgangsort für die Suche, den Ordner wo die Anwendung liegt, oder das Arbeitsverzeichnis? Kann man die Suchpfade ggf. zur Laufzeit ändern? Vielleicht sogar auch für alle anderen Bibliotheken?
Hoffe es gibt ne Lösung..
1. PATH - ist wirklich nicht sehr schön und verlangt eine Installation.
2. Funktionen manuell laden - wenn das so aufwendig ist wie es sich anhört..
3. Programm im bin-Ordner - ich würde es schon gerne im Stammordner haben, wie soll es der Benutzer sonst ausführen. Eine Verknüpfung im Programmordner ist unschön und würde den Speicherort des Programms bindend machen.
Also, wo steht geschrieben, dass z.B. Qt-Plugin-DLLs in einem Unterordner mit dem Namen des Plugins liegen müssen, das wird doch sicherlich beim linken in die Anwendung gemeißelt, kann man das nicht ändern? Im erzeugten makefile konnte ich diesbezüglich nichts direkt finden..
Speziell geht es mir um die QCA-(Crypto-)API, seine DLL akzeptiert der im Programmordner, aber einige Funktionen werden als Plugins zur Verfügung gestellt und liegen in <Qt-Dir>/plugins/crypto, ich fürchte dass die Haupt-Bibliothek explizit dort nach ihnen sucht, also in einem Unterordner namens crypto - mann was haben die sich nur dabei gedacht, ist doch krank: die Haupt-DLL ist ja auch nicht in diesem Ordner.. Wenn dies der Fall sein sollte gibts wohl keine Lösung? Was nimmt er als Ausgangsort für die Suche, den Ordner wo die Anwendung liegt, oder das Arbeitsverzeichnis? Kann man die Suchpfade ggf. zur Laufzeit ändern? Vielleicht sogar auch für alle anderen Bibliotheken?
Hoffe es gibt ne Lösung..
Bei PlugIns bist Du nicht auf den Ordner festgelegt, wenn Du sie mit dem QPlugInLoader lädst. Also auch quasi manuell, aber ist evtl. einfacher als mit z.B. LoadLibrary
Code: Alles auswählen
QDir pluginsDir = QDir(qApp->applicationDirPath()+QDir::separator()+"MeinPlugInDir");
QStringList pluginFileNames;
foreach (QString fileName, pluginsDir.entryList(QDir::Files))
{
if (QLibrary::isLibrary(fileName))
{
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = loader.instance();
if (plugin)
{
PlugInInterface *meinPlugIn= qobject_cast<PlugInInterface *>(meinPlugin);
if (meinPlugIn)
m_meinePlugIns.push_back(meinPlugIn);
else
plugin->deleteLater();
}
else
QMessageBox::warning(0, tr("Error"), tr("Error loading plugin %1\n").arg(fileName)+loader.errorString());
}
}
Bitte seid so nett und ändert den Titel von Beiträgen die gelöst wurden, auf [gelöst] Beitragstitel
Hallo
den Suchpfad für die plugins kannst du mittels dieser Methoden von
QApplication (geerbt von QCoreApplication) manipulieren.
removeLibraryPath
ibraryPaths
setLibraryPaths
addLibraryPath
Danach werden die plugins auch automatisch aus einem andere Verzeichnis geladen und ein händisches Laden mittels QPluginLoader ist nicht notwendig.
mfg
den Suchpfad für die plugins kannst du mittels dieser Methoden von
QApplication (geerbt von QCoreApplication) manipulieren.
removeLibraryPath
ibraryPaths
setLibraryPaths
addLibraryPath
Danach werden die plugins auch automatisch aus einem andere Verzeichnis geladen und ein händisches Laden mittels QPluginLoader ist nicht notwendig.
mfg
Volker: Hört sich gut an, damit könnte ich wohl erreichen, dass die Plugins sogar kein Unterverzeichnis mehr benötigen. Aber was ist mit PlugInInterface und m_meinePlugIns? Ist letzteres einfach nur eine Liste, deren Elemente am Ende deleted werden müssen? Und woher bekomme ich das PlugInInterface?..
isifloh: Danke auch dir, damit kann ich wenigstens einen gemeinsamen Unterordner für die Plugin-Ordner beliebig wählen.
isifloh: Danke auch dir, damit kann ich wenigstens einen gemeinsamen Unterordner für die Plugin-Ordner beliebig wählen.
Das PlugInInterface ist die Schnittstelle zu Deinen PlugIns, oder geht's dir nur um PlugIns die schon bei Qt mitgeliefert werden?
Guck Dir einfach mal das PlugIn Howto in der Qt Doku an:
http://doc.trolltech.com/4.3/plugins-howto.html
Da würde dann z.B. dem von mir angegebenen PlugInInterface das FilterInterface entsprechen.
Bzgl. des Deletes: Normalerweise leitet die implementierte Klasse ja von QObject ab, so dass Du mit setParent auch ein Parent setzen kannst und dich dann nicht unbedingt selbst um das löschen kümmern musst. Wenn du das nicht machst, musst du aber ja irgendwo das ganze wieder freigeben, daher die Liste.
Du kannst aber natürlich auch irgendwo anders die Referenz speichern. War nur ein Beispiel.
Guck Dir einfach mal das PlugIn Howto in der Qt Doku an:
http://doc.trolltech.com/4.3/plugins-howto.html
Da würde dann z.B. dem von mir angegebenen PlugInInterface das FilterInterface entsprechen.
Bzgl. des Deletes: Normalerweise leitet die implementierte Klasse ja von QObject ab, so dass Du mit setParent auch ein Parent setzen kannst und dich dann nicht unbedingt selbst um das löschen kümmern musst. Wenn du das nicht machst, musst du aber ja irgendwo das ganze wieder freigeben, daher die Liste.
Du kannst aber natürlich auch irgendwo anders die Referenz speichern. War nur ein Beispiel.
Bitte seid so nett und ändert den Titel von Beiträgen die gelöst wurden, auf [gelöst] Beitragstitel
Jain. Es ist nicht von Qt, aber auch nicht von mir. Aber vielleicht benötige ich später Qt-Plugins. Es gibt eine Erweiterung die nennt sich "Qt Cryptographic Architecture" (QCA), diese hat Plugins erstellt und ins Qt-Verzeichnis kopiert, und um diese geht es mir momentan.Volker hat geschrieben:Das PlugInInterface ist die Schnittstelle zu Deinen PlugIns, oder geht's dir nur um PlugIns die schon bei Qt mitgeliefert werden?
Hab mir mal den Quellcode angeschaut, über
Code: Alles auswählen
QDir dir(libpath.filePath(PLUGIN_SUBDIR));Code: Alles auswählen
ProviderItem *i = ProviderItem::load(fname);Code: Alles auswählen
#define PLUGIN_SUBDIR "crypto"Ich denke das Hinzufügen eines neuen Library-Suchpfades ist erstmal die einfachste Möglichkeit, auch wenn es den Nachteil hat, dass DLLs nun im Programmverzeichnis UND einem frei wählbaren Unterordner liegen - eigentlich wollte ich nur eines von beiden.
wobei die dir auch nur bei reinen "QTPlugins" helfen, also die standard plugins die QT mitbringt oder eigene Plugins der QT Plugin Typen / treiber.removeLibraryPath
ibraryPaths
setLibraryPaths
addLibraryPath
Hast Du ne eigene Plugin engine, musst dich wirklich haendisch drum kuemmern.
PATH ist eine umgebungsvariable ....1. PATH - ist wirklich nicht sehr schön und verlangt eine Installation.
damit wird die beim starten des prozesses vom elternprozess (Linux meistens die shell, unter windows der explorer die cmd shell oder weas sonst auch immer) geerbt, besser gesagt kopiert.
mit getenv kann man die auslesen und mit setenv lesen. Was du mit setenv schreibst, gilt aber nur fuer deinen prozess, sprich andere prozesse werden davon nicht beeinflusst und beim neustarten ist alles wieder weg.
Das bietet sich geradezu an fuer lokale aenderungen ....
Ciao ...
Ja und d.h. dass man VOR dem Starten des Programms diese Variable setzen muss -> Installation oder Startscript. Wenn man das in main() mit setenv setzen würde, wäre es doch längst zu spät da er vorher das Vorhandensein der DLLs prüft oder nicht? Glaube ich hatte das aber mal probiert und setenv kannte er nicht, nur getenv... Hab grad Win neu installiert und kanns noch nicht testen...RHBaum hat geschrieben:PATH ist eine umgebungsvariable ....
nicht unbedingt ....Ja und d.h. dass man VOR dem Starten des Programms diese Variable setzen muss
du musst nur vor dem laden der plugins dazukommen, die Path variable anzupassen.
dann kannst deinen pluginpfad irgendwo in irgendwelchen settings stehen haben, nach dem starten des programms und lesen der settings wird der lokale $PATH angepasst (getenv / setenv), und danach die plugins geladen, und voiala, die plugins werden aus deinem Verzeichniss geladen und die anderen Applikationen kriegen davon gar nix mit, und du brauchst auch kein Script vorher ....
BTW, die kindprozesse erben die umgebungsvariablen natuerlich ...
Ciao ...
Genau, die qt-plugin-libs (derzeit sowieso nur eine) konnte ich ja bereits dank isifloh erfolgreich in einen gemeinsamen Unterordner verschieben mit
Das Problem war jetzt nur dass es 2 Orte gibt in denen DLLs auftauchen, der bin-Unterodner (Plugins) und der Programmordner (alle anderen DLLs).
Plugins können nicht im Programmverzeichnis liegen, da sie ihren eigenen Unterordner verlangen (dumme dumme dumme Idee) und die anderen DLLs können nicht in einem Unterodner liegen, da dieser wärend dem Laden der Anwendung dem System nicht als Bibiliotheks-Pfad bekannt ist.
Eine mögliche Lösung die ich - vielleicht - akzeptieren würde wäre noch ein nicht-Qt-Starterprogramm welches systemabhängig geschrieben werden müsste ähnlich einer Verknüpfung, nur hab ich dazu kein Bock und würde ich es unter win mit g++/mingw compilieren bräuchte ich trotzdem die mingwm10.dll, lohnt sich also nicht wirklich.
Also ich werde es wohl so belassen wie es ist. Vielen Dank an alle die geholfen haben,
FaS
Code: Alles auswählen
QCoreApplication::addLibraryPath( "bin" );Plugins können nicht im Programmverzeichnis liegen, da sie ihren eigenen Unterordner verlangen (dumme dumme dumme Idee) und die anderen DLLs können nicht in einem Unterodner liegen, da dieser wärend dem Laden der Anwendung dem System nicht als Bibiliotheks-Pfad bekannt ist.
Eine mögliche Lösung die ich - vielleicht - akzeptieren würde wäre noch ein nicht-Qt-Starterprogramm welches systemabhängig geschrieben werden müsste ähnlich einer Verknüpfung, nur hab ich dazu kein Bock und würde ich es unter win mit g++/mingw compilieren bräuchte ich trotzdem die mingwm10.dll, lohnt sich also nicht wirklich.
Also ich werde es wohl so belassen wie es ist. Vielen Dank an alle die geholfen haben,
FaS
Dll's werden nie "vor dem Start" geladenich glaube er redet von den QT DLLs die nunmal VOR dem Programmstart geladen werden.
Die frage ist nur, ob man an den zeitpunkt vor den dynamsichen laden rankommt, bzw. ob man sich da ned mehr probleme einhandeln kann.
Das hauptproblem bei dem auch von M$ benutzen prinzip mit der statischen BindeLib ist, das da das dynamische laden der dlls meist uber statische klassenmember (also quasi global) und damit vor dem main() erfolgt.
wenn das funktioniert, dann werden die Dlls definitv danach (nach diesem aufruf) geladen ....QCoreApplication::addLibraryPath( "bin" );
Was darauf hindeutet, das QT den lademechanismus fuer Dlls, zumindest fuer die eigenen plugins, von Windows aushebelt.Plugins können nicht im Programmverzeichnis liegen, da sie ihren eigenen Unterordner verlangen (dumme dumme dumme Idee)
Bei loadlibrary ist definiert, das windows zuerst im verzeichnis des binaries sucht ....
Die QT wird beim QT-plugin-laden also irgendwie selber pfade auswerten und die dlls nur mit vollstaendigen pfad versuchen zu laden, was eine manipulation von der $PATH sowieso sinnlos macht.
Glaub hier versuchen die QT zu manipulieren waere ein weg mit zu viel aufwand ...
du rufst dochDas Problem war jetzt nur dass es 2 Orte gibt in denen DLLs auftauchen, der bin-Unterodner (Plugins) und der Programmordner (alle anderen DLLs).
QCoreApplication::addLibraryPath( "bin" ); auf ?
ermittel doch mal den absoluten pfad deiner anwendung, und adde den auch als libraryPfad ueber die funktion ?
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
wuerde mich wundern wenn die QT expliziet das dir des binaries als Lib pfad unterbindet ....
Ich mach mit den QT plugins ned viel, wir schreiben mehr eigene Plugins wo die schnittstellen QT frei sein muessen (nicht jeder unserer Zulieferer soll sich die QT kaufen) .... deshalb kenn ich mich auch mehr mit so generellen Dll probs aus, ned so mit dem QT Plugin spezifischen zeugs ...
Ciao ...
Ja, die Plugins, das funktioniert nur mit den Plugins: wie weiter oben schon geschrieben hab ich mir den Lademechanismus des QCA-Plugins, um das es mir ging angesehen: Der sucht alle seine DLLs in <alle QCoreApplication::libraryPaths()>/PLUGIN_SUBDIR/*, wobei PLUGIN_SUBDIR ein #define für "crypto" ist.RHBaum hat geschrieben:wenn das funktioniert, dann werden die Dlls definitv danach (nach diesem aufruf) geladen ....
Der sucht die Qt-Plugins mit Hilfe meines addLibraryPath() ja nicht direkt in bin, sondern in bin/<pluginname>/*. Der Pfad meiner Anwendung ist da standardmäßig schon drin, aber dann hätte ich dort doch lauter <pluginname>-Unterverzeichnisse; ein gemeinsames Unterverzeichnisse für diese Plugin-Verzeichnisse ist also die einzige Möglichkeit, wenn ich die Plugins nicht manuell ändern will.RHBaum hat geschrieben:du rufst doch
QCoreApplication::addLibraryPath( "bin" ); auf ?
ermittel doch mal den absoluten pfad deiner anwendung, und adde den auch als libraryPfad ueber die funktion ?
-----
Ist doch toll, Qt-Zeugs ist erledigt, jetzt müssen nur noch alle anderen (nicht-Qt-Plugin-) DLLs in das bin-VerzeichnisRHBaum hat geschrieben:deshalb kenn ich mich auch mehr mit so generellen Dll probs aus, ned so mit dem QT Plugin spezifischen zeugs ...
Hmm hört sich interessant an, dachte mir da mach ich das mal nach, statische Variablen in main.cpp müssten ja zuerst ausgewertet werden wenn main.cpp zuerst dem Linker übergeben wird oder nicht? Jedenfalls hab ich folgendes an den Anfang geschrieben:RHBaum hat geschrieben:Das hauptproblem bei dem auch von M$ benutzen prinzip mit der statischen BindeLib ist, das da das dynamische laden der dlls meist uber statische klassenmember (also quasi global) und damit vor dem main() erfolgt.
Code: Alles auswählen
#include <cstdlib>
class PathChanger
{
public:
PathChanger();
};
PathChanger::PathChanger()
{
putenv( "PATH=bin" );
}
static PathChanger pathChanger;Naja das ganze funktioniert für die ganzen DLLs jedenfalls nicht, vielleicht hast du noch ein Tipp?
Wenn ich im System eine Umgebungsvariable "bin" zu $PATH hinzufüge funktioniert das ganze, eine relative Angabe ist also in Ordnung.