Domanda

Ho un'applicazione C ++ multipiattaforma che è suddivisa in diverse librerie condivise e carica funzionalità aggiuntive dalle librerie condivise plug-in. Le librerie di plugin dovrebbero essere autosufficienti e funzionare da sole, senza conoscenza o dipendenza dall'applicazione chiamante.

Uno dei plugin contiene codice copiato dall'applicazione principale, quindi contiene nomi di simboli duplicati a quelli nel motore. (Sì, lo so che in genere è un no-no, ma al momento della stesura del plugin il motore era un binario monolitico e non poteva condividere le librerie.) Su Windows, tutto funziona bene. Su Linux ottenevamo segfault. Osservando la traccia dello stack dell'errore, si stava verificando nel plugin quando si chiamavano funzioni nel nome della classe duplicata. Sembrava che il motore e il plug-in avessero versioni leggermente diverse del codice condiviso (alcune funzionalità di classe sono state commentate nel plug-in). Era come se il plugin ottenesse i suoi simboli di runtime collegati al motore anziché al proprio. Abbiamo & Quot; riparato & Quot; il problema modificando i parametri di dlopen in dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL).

Ma quando riscriviamo il motore per essere diviso in librerie condivise (per l'eventuale scopo di riutilizzo nei plugin), otteniamo di nuovo l'errore segfault. E guardando la traccia dello stack, va dal motore - & Gt; plugin - > motore.

Esiste un modo per specificare che il linker di runtime non associ i simboli del plug-in al motore (specialmente se sono definiti nel plug-in)?

Grazie! Matt


Modificato 2009-12-3

Ho prima provato a racchiudere il codice del plugin nel suo spazio dei nomi. Non ha funzionato perché è staticamente collegato a una libreria collegata anche al motore. Le versioni della libreria statica sono diverse, quindi segfault!

Quindi ho modificato la build del motore e le sue librerie devono essere collegate staticamente. E quando lo eseguo, non ho più il problema. Quindi sembra che sia stato il risultato dell'esportazione dei simboli della libreria condivisa e del successivo trasferimento dinamico nel plug-in quando è stato aperto. Ma quando tutto il codice del motore è in un singolo eseguibile, non esporta i suoi simboli (quindi non cerca di riposizionare i simboli del plugin nel motore).

Ho ancora un problema, dato che esiste una versione parallela del programma (che utilizza Open-MPI) e che ottiene ancora il segfault. Sembra che stia ancora esportando i simboli del motore e trasferendo i plugin. Ciò potrebbe avere a che fare con il modo in cui Open-MPI esegue l'applicazione.

Esistono flag di linker che potrebbero essere utilizzati nella libreria condivisa del plug-in che potrebbero indicare di non spostare dinamicamente i simboli in fase di esecuzione? O per nascondere i suoi simboli in modo che non vengano trasferiti? Ho provato -s (& Quot; Ometti tutte le informazioni sui simboli & Quot;) ma a quanto pare non ha cambiato i simboli dinamici (controllato usando nm -D <plugin>).

È stato utile?

Soluzione

Penso di aver trovato la soluzione, il flag linker -Bsymbolic. Essenzialmente questo flag aggiunge un flag nella libreria condivisa per dire al linker di runtime di provare prima a risolvere i nomi dei simboli. Il motore è stato in grado di funzionare correttamente con il plug-in in tutti i casi (exe monolitico, exe con librerie condivise, plug-in con e senza involucro dello spazio dei nomi) quando il plug-in era collegato con quel flag.

Sembra che ci siano alcuni detrattori con avvertenze su <=>:
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

Ma considerando i loro avvertimenti e quale sia l'intenzione del plugin, penso che sia l'opzione giusta per me. Almeno per ora.

Altri suggerimenti

Sono d'accordo con Glen: non lo risolverai davvero a meno che non modifichi i nomi delle classi, possibilmente tramite namespace. Anche 36 file probabilmente impiegheranno meno tempo a modificarsi rispetto al tentativo di risolverlo in modo affidabile senza cambiare i nomi dei simboli.

Inizia identificando tutte le classi i cui nomi devono essere modificati. Il tuo linker probabilmente li elenca già per te. Quindi cambierei i nomi di entrambi insiemi di classi (da Foo a Engine :: Foo e Plugin :: Foo per esempio) almeno temporaneamente. In questo modo è possibile ottenere il compilatore per trovare tutti i riferimenti alle classi problematiche. Scambia il codice sorgente del plug-in fino a quando il plug-in non viene compilato con riferimenti ai nomi di nuove classi di plug-in corretti. Una volta fatto ciò, riporta le classi Engine :: ai loro vecchi nomi (a meno che tu non voglia modificare in modo permanente anche la fonte del motore, cosa che sembra che tu non faccia). Il plugin ora dovrebbe compilare e collegarsi alle classi corrette, con un nome univoco.

Vorrei semplicemente racchiudere TUTTO il codice del plugin con uno spazio dei nomi PluginX. Questo sicuramente ti salverà da questi errori. È comunque un'ottima, importante pratica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top