lunga storia di quello che sto cercando di realizzare
Sto lavorando su un programma che carica dinamicamente DLL come plugin. Sto compilando il programma utilizzando Microsoft Visual C++ 2008. Tuttavia, supponiamo che qualsiasi versione di Visual C++ con cui funziona Qt debba essere supportata. La struttura della directory del programma è il seguente:C++: Manifest e DLL caricamento dinamico di directory diversa
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| program.exe
program.exe
rileva tutti i file DLL plugin, esegue LoadLibrary() su di loro e chiama una certa funzione di firma per scoprire se in realtà è un plugin o meno. Funziona piuttosto bene su computer che dispongono di videoregistratore per MSVC90 installato. Naturalmente, per far funzionare il programma su tutti i computer, devo ridistribuirlo con i file msvc * .dll e con il file manifest appropriato. Anche le DLL Qt richiedono l'esecuzione della redist.
Ora, ho impostato cmake per copiare automaticamente su DLL di redist appropriate e manifestare in base alla versione di Visual Studio selezionata. Per semplicità continuiamo a supporre che sto lavorando con MSVC90. Quando il redist viene copiato nella directory del programma il layout è simile al seguente:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| msvcm90.dll
| msvcp90.dll
| msvcr90.dll
| Microsoft.VC90.CRT.manifest (I'm also aware that this file is bugged in VS2008)
| program.exe
Per quanto riguarda il bug nel file manifesto: http://www.cmake.org/pipermail/cmake/2008-September/023822.html
Il problema
Il programma con questo layout ora funziona su computer che non hanno il redist installato, ma i plug-in non vengono caricati. Al fine di ottenere i plugin per caricare devo fare una delle seguenti:
- Copiare il file manifesto per
plugins/
directory. Rimuovi tutti i riferimenti ai file msvc * .dll dal file manifest. Funziona ma non è bello perché dovrei supportare diverse versioni dei file manifest modificati a seconda della versione di MSVC utilizzato. Inoltre, non ho idea se questo non si interromperà con Visual Studio diverso dal 2008. - Copia intera redist nella directory
plugins/
. Questo non richiede alcuna modifica al file manifest, ma oraprogram.exe
tenta stupidamente di caricare i file msvc * .dll pensando che siano plugin. Naturalmente, questo fallisce con grazia, quindi non viene fatto alcun danno. L'altro svantaggio è che la dimensione del pacchetto del programma aumenta di oltre 1 MB. Entrambi questi problemi sono qualcosa con cui posso convivere, però. - Compila plugin con l'interruttore/MT. Un breve test ha dimostrato che questo funziona davvero, ma non sono sicuro che non cambierà nulla in futuro se sia Qt che
program.exe
sono/MD.
La domanda (s)
Qual è la soluzione migliore? Qual è la soluzione corretta? Se esiste più di una soluzione corretta, qual è la migliore pratica? Sono la prima persona a provare a farlo?
Update 1 (18 nov 2012)
Mentre la domanda rimane senza risposta ho deciso di andare per il percorso che fa sì che il minimo mal di testa. Fino ad ora ho utilizzato la soluzione numero 1 e ho deciso di seguirlo. Se CMake rileva che l'utente sta utilizzando una versione MSVC diversa rispetto al 2008, verrà visualizzato un messaggio di avviso che informa che la confezione automatica non è completamente supportata.
Perché non si collega in modo statico il tempo di esecuzione per l'app e per i plug-in? –
Qt richiede già il videoregistratore, quindi dovrò includerlo comunque. Inoltre ci sono problemi con l'allocazione delle risorse quando la risorsa viene allocata in un'entità collegata staticamente e poi rilasciata in un'altra: non è sicura e il programma potrebbe bloccarsi. Non so come si comporterà con Qt se Qt è/MD. – ZalewaPL
Penso che dovresti lasciare che gli autori dei plugin decidano come vogliono collegarsi alla libreria di runtime e non provare a forzarli a collegarsi dinamicamente a una particolare versione del tempo di esecuzione. Per quanto riguarda i problemi di allocazione che hai menzionato, se stai chiamando il plugin per allocare una risorsa, allora dovresti richiamare nel plugin per liberare la risorsa. –