2016-05-30 27 views
15

Sto compilando librerie Linux (per Android, usando NDK's g ++, ma scommetto che la mia domanda ha senso per qualsiasi sistema Linux). Quando consegna queste librerie ai partner, ho bisogno di contrassegnarle con un numero di versione. Devo anche essere in grado di accedere al numero di versione programmaticamente (per visualizzarlo in una finestra di dialogo "Informazioni" o una funzione GetVersion per esempio).Modifica libreria condivisa Linux (.so file) dopo la compilazione

Prima di compilare le librerie con un flag non invertito (versione 0.0) e ho bisogno di cambiare questa versione in una reale quando ho finito di testare prima di inviarlo al partner. So che sarebbe più semplice modificare il sorgente e ricompilare, ma non vogliamo farlo (perché dovremmo testare di nuovo tutto se ricompiliamo il codice, pensiamo che sarebbe meno incline agli errori, vedere i commenti a questo post e infine perché il nostro ambiente di sviluppo funziona in questo modo: eseguiamo questo processo per i binari di Windows: impostiamo una stringa di versione 0.0 resources (.rc) e in seguito la modificheremo usando verpatch ... vorremmo lavorare con lo stesso tipo di processo durante la spedizione dei binari di Linux).

Quale sarebbe la migliore strategia qui? Per riassumere, i requisiti sono:

  1. binari compilare con versione "unset" (0.0 o qualsiasi altra cosa)
  2. in grado di modificare questa versione "unset" per uno specifico senza dover ricompilare il binario (idealmente, eseguire un terzo comando dello strumento del partito, come facciamo con verpatch sotto Windows)
  3. in grado di avere il codice della libreria recuperare è informazioni sulla versione in fase di esecuzione

Se la vostra risposta è "rinominare il .so", t gallina si prega di fornire una soluzione per 3 .: come recuperare il nome della versione (cioè il nome del file) in fase di esecuzione.

Stavo pensando ad alcune soluzioni ma non ho idea se potessero lavorare e come ottenerle.

  • avere una variabile di versione (uno string o 3 int) nel codice e hanno un modo per cambiarlo nel file binario in seguito? Usando un binario sed ...?
  • Avere una variabile di versione all'interno di una risorsa e avere un modo per modificarla in un file binario in un secondo momento? (come facciamo per win32/win64)
  • Utilizzare un campo del .so (come SONAME) dedicato a questo e avere uno strumento che consente di cambiarlo ... e renderlo accessibile dal codice C++.
  • Rinominare la modifica + SONAME (non ha trovato il modo in cui è possibile ottenerlo) ... e trovare un modo per recuperarlo dal codice C++.
  • ...

Nota che usiamo QtCreator per compilare i file Android .so, ma non possono fare affidamento su Qt. Quindi utilizzare le risorse Qt non è una soluzione ideale.

+1

Si teme che la ricompilazione dello stesso codice esatto con una stringa di versione scambiata possa rompere le cose e necessiti di nuovi test, ma sono perfettamente soddisfacenti con una soluzione che comporta l'hacking di uno script che applica patch alla stringa modificata nel binario? Interessante. – Phillip

+0

Le tue osservazioni hanno perfettamente senso. In realtà lo facevamo in quel modo: cambia il numero di versione (a 3.2 per esempio) nel codice e ricompilalo. Siamo una piccola struttura, persone che fanno sia lo sviluppo che l'integrazione ... quindi, lo sviluppatore che fa questo spesso dimentica di reimpostare la stringa della versione su 0.0 e poi in seguito si ottengono i binari di sviluppo contrassegnati 3.2 quando non sono sicuramente la versione 3.2 ... quella è perché contrassegnare i binari una volta che la compilazione dei post sembrava essere più sicura per noi (e questo è il modo in cui finiamo per lavorare sotto Windows). – jpo38

+0

Il mio commento si applica ancora :-) Perché non risolvi il problema alla radice e modifica l'ambiente di costruzione per riportare il numero di versione a 0.0 per qualsiasi build di debug? Il modo più semplice per farlo sarebbe utilizzare una definizione del preprocessore per il numero di versione. La cosa buona di questa soluzione è che può essere facilmente adottato per includere per es. ID di revisione nelle stringhe di versione di build di debug. – Phillip

risposta

2

La discussione con Slava mi ha fatto capire che qualsiasi const char* era effettivamente visibile nel file binario e poteva quindi essere facilmente adattato a qualsiasi altra cosa.

ecco un bel modo per risolvere il mio problema:

  1. creare una libreria con:
    • una definizione di const char version[] = "VERSIONSTRING:00000.00000.00000.00000"; (ne abbiamo bisogno abbastanza a lungo come si può modificare in seguito in modo sicuro il binario file contenuto ma non estenderlo ...)
    • a GetVersion una funzione che pulisce la variabile version sopra (rimuovere VERSIONSTRING: e l'inutile 0). Sarebbe tornare:
      • 0.0 se version è VERSIONSTRING:00000.00000.00000.00000
      • 2.3 se version è VERSIONSTRING:00002.00003.00000.00000
      • 2.3.40 se version è VERSIONSTRING:00002.00003.00040.00000
      • ...
  2. compilare la libreria, le Il nome di t esso mylib.so
  3. caricarlo da un programma, per chiedere la sua versione (chiamata GetVersion), restituisce 0.0, non è una sorpresa
  4. Creare un piccolo programma (lo ha fatto in C++, ma potrebbe essere fatto in Python o qualsiasi altro languauge) che verrà:
    • carico un intero contenuto di un file binario in memoria (usando std::fstream con std::ios_base::binary)
    • trovano VERSIONSTRING:00000.00000.00000.00000 in esso
    • conferma compare una sola volta (per essere sicuri che non modifichiamo qualcosa che abbiamo fatto no t mean to, ecco perché prefisso la stringa con VERSIONSTRING, per renderlo più unic ...)
    • cerotto a VERSIONSTRING:00002.00003.00040.00000 se il numero binario previsto è 2.3.40
    • salvare il file binario di ritorno da contenuti patch
  5. Patch mylib.so utilizzando lo strumento di cui sopra (richiesta versione 2.3 per esempio)
  6. eseguire lo stesso programma come passo 3., ora riporta 2.3!

Nessuna ricompilazione o collegamento, hai corretto la versione binaria!

+0

Non è necessario caricare l'intero file in memoria e quindi sovrascrivere l'intero file. Puoi usare 'stringhe' per trovare la tua stringa e ti dirà l'offset del file, quindi apri quel file per scrivere, posizionare e sovrascrivere la stringa. – Slava

+0

@ Slava: sicuro. Ho provato a codificarlo velocemente per verificare il concetto, può essere sicuramente ottimizzato. Il caricamento dell'intero file facilita il controllo della stringa una sola volta. – jpo38

2

Ho paura che tu abbia iniziato a risolvere il tuo problema dalla fine. Prima di tutto SONAME viene fornito al momento del collegamento come parametro del linker, quindi all'inizio devi trovare un modo per ottenere la versione dall'origine e passare al linker.Una delle possibili soluzioni - utilizzare ident utilità e fornire una stringa di versione in binario, ad esempio:

const char version[] = "$Revision:1.2$" 

questa stringa dovrebbe apparire nel binario e ident utilità lo rileverà. Oppure puoi analizzare direttamente il file sorgente con grep o qualcosa di simile. Se non v'è possibilità di conflitti messo marcatore aggiuntivo, che è possibile utilizzare in seguito per rilevare questa stringa, ad esempio:

const char version[] = "VERSION_1.2_VERSION" 

Così si rilevano il numero di versione sia da file di origine o da .o di file e basta passarlo a linker . Questo dovrebbe funzionare.

Come per la versione di debug per avere la versione 0.0, è semplice: basta evitare il rilevamento quando si crea il debug e si usa solo 0.0 come versione incondizionata.

Per il sistema di generazione di terze parti, si consiglia di utilizzare cmake, ma questa è solo una mia preferenza personale. La soluzione può essere facilmente implementata anche nel Makefile standard. Non sono sicuro di qmake.

+0

La proposta richiede che il numero di versione sia specificato nel codice al momento della compilazione. Questo non risponde in modo preciso alla mia domanda che richiede un modo per modificare il numero di versione direttamente all'interno di un file .so già generato. Ma forse quello che sto chiedendo è impossibile da fare sotto Linux (mentre è fattibile sotto Windows) ... Aspetterò la fine del periodo di taglia per vedere se ottengo qualcosa di meglio. Grazie per l'aiuto. – jpo38

+0

Prima di tutto hai chiesto di cambiare SONAME senza ricompilazione, la mia risposta descrive come farlo. Devi essere più chiaro con le tue esigenze. – Slava

+0

Non capisco. Come posso fare ciò che proponi senza compilare quando proponi di "ottenere la versione per il sorgente". Il mio obiettivo è compilare il file .so con la versione "0.0" e successivamente cambiarlo in qualcos'altro senza ricompilare/linkare (usando uno strumento esterno). – jpo38

Problemi correlati