2015-04-09 11 views
8

Nelle nostre file di origine di solito abbiamo una stringa di versione del genere:evitare che gcc di rimuovere una variabile non utilizzata

static const char srcvers[] = "VERSION/foo.c/1.01/09.04.15"; 

Quando la stringa non è ottimizzato via, è molto utile in certi casi, come si può determinare la versione di ciascun file sorgente collegato a un eseguibile semplicemente chiamando strings a.out | grep VERSION.

Purtroppo lo è ottimizzato via da gcc (utilizzando '-O'). Quindi la mia domanda è, c'è un modo semplice (un commutatore sarebbe fantastico) per fare in modo che gcc mantenga quella variabile (il suo nome è sempre lo stesso) senza disattivare altre ottimizzazioni.

Modifica

Quali sono, a mio parere, rende la questione diversa da that one, è che sto speravo di trovare una soluzione per la quale io non avrei dovuto toccare migliaia di file di origine.

+0

Cosa ne pensi di aggiungere l'opzione '-v' su tutto il tuo binario che mostra questo var? –

+0

Forse prova a ingannare 'gcc' nel pensare che la variabile sia usata (qualcosa come' strlen (srcvers); ')? –

+3

Ho provato a renderlo 'volatile'? Dovrebbe funzionare: 'volatile static const char srcvers [] =" VERSION/foo.c/1.01/09.04.15 ";' –

risposta

17

È possibile utilizzare __attribute__((used)) gcc (funziona anche in clang) specifico (vedo che la questione è aggiunto gcc) attribuisce per questo:

Questo attributo, attaccato a una funzione, significa che il codice deve essere emessa per la funzione anche se sembra che la funzione non sia referenziata. Ciò è utile, ad esempio, quando la funzione è referenziata solo in assembly inline.

Da https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

Demo:

$ cat a.c 
static const char srcvers[] __attribute__((used)) = "VERSION/foo.c/1.01/09.04.15"; 
$ gcc -O3 -c a.c 
$ strings a.o 
VERSION/foo.c/1.01/09.04.15 

È possibile utilizzare alcuni #if s e #define s per rendere questo terser e anche compilare su compilatori che non supportano questa estensione.

+2

Sebbene l'estratto della documentazione descriva l'uso di questo attributo con le funzioni, lo stesso attributo può anche essere utilizzato con le variabili, a condizione che abbiano una memoria statica (come in questo caso). –

+0

ottima idea, grazie. Ma la soluzione ideale era quella in cui non avrei avuto bisogno di modificare ogni file sorgente. –

+0

@IngoLeonhardt - puoi fare qualcosa di simile con uno script linker. –

3

Anche la dichiarazione della variabile volatile può essere d'aiuto. Ecco perché viene utilizzato in primo luogo, impedendo eventuali ottimizzazioni da parte del compilatore riguardo a tale variabile.

+0

Aiuta sicuramente; Ho già controllato. Ma ancora una volta, questo significherebbe toccare ogni singolo file :-(. Comunque, –

+0

Si noti che questo * è definito dall'implementazione *. Non è garantito che funzioni, poiché lo standard richiede solo che 'volatile' influenzi gli accessi alla variabile. Se la variabile non viene mai utilizzata, il compilatore può rimuoverla liberamente – user694733

4

Come ho capito la tua domanda, è necessario aggiungere la stringa di versione a ogni file oggetto senza toccare le fonti. Può essere fatto usando il prossimo modo.

Creare file di intestazione, ad esempio include/version.h:

#ifndef VERSION_H 
#define VERSION_H 

static const char _ver[] __attribute__((used)) = "VERSION/foo.c/1.01/09.04.15"; 

#endif /* VERSION_H */ 

Poi, nel tuo Makefile (o qualunque sia il vostro sistema di compilazione è) aggiungere prossimo gcc bandiera:

CPPFLAGS += -include include/version.h 

Naturalmente dovrebbe essere passato a gcc, ad esin questo modo:

%.o: %.c 
    $(CC) $(CFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).c 

Ora si può osservare la stringa _ver compilato per ogni file oggetto:

$ objdump -DS src/main.o | grep _ver 

che vi mostrerà qualcosa di simile:

Disassembly of section .rodata._ver: 
00000000 <_ver>: 
+0

la stringa di versione è già presente ma è ottimizzata (e ovviamente ho bisogno di quella con date come '03 .01.01 ', alcuni file sono veramente vecchi). wih '-include' puzza un po 'come se potessi usarlo per risolvere comunque il problema Grazie ancora –

+0

Ah, i tuoi file sorgente hanno versioni diverse, vedo.Penso che quella versione sia sinonimo di progetto stesso –

+0

no che sarebbe troppo facile (in effetti si tratta di un'informazione aggiuntiva già disponibile, ma è necessario essere certi che un certo cambiamento in un file incluso in una libreria .. sia collegato o meno) –

1

Come sembra che tutto le soluzioni richiedono una sorta di decorazione della stringa di versione nel sorgente, può aiutare a definire una macro contenente tutta la sintassi necessaria e quindi utilizzare questa macro nel sorgente o lui Ader file ogni volta che necessità:

#define SRCVERSION(file, version, data) static const char _ver[] __attribute__((used)) = "VERSION/" file "/" version "/" date; 

Poi nell'origine appena messo

SRCVERSION("foo.c", "1.01", "09.04.15") 

La macro può essere in un file centrale di intestazione di progetto o sulla riga di comando del compilatore.

In questo modo, almeno non è necessario toccare nuovamente tutti i file di origine se si desidera modificare qualcosa sulla definizione.

Nota come la definizione di macro utilizza la concatenazione di stringhe per creare la stringa di versione finale. Inoltre contiene il punto e virgola finale in modo da poter rimuovere tutto definendo una macro vuota se necessario.

0

Sei preoccupato per gcc rimuovendo una variabile static char[] inutilizzata. AFAIK, il compilatore ha ragione a farlo.

Altre risposte hanno fornito un suggerimento per migliorarlo. Ma non vuoi cambiare il codice sorgente di migliaia di file.

Quindi, potresti forse cambiare la tua build (ad esempio un po 'di Makefile) in modo che ogni tale file sorgente che usa il tuo trucco (che è leggermente sbagliato, come discusso qui ...) non avrebbe bisogno di essere cambiato. Quindi potresti specificamente invoke GCC. Volete

static const char _ver[] __attribute__((used)); 

(questa è una dichiarazione, non una definizione) da compilare prima di ogni altra cosa. Inserire la riga sopra in un file _declare_ver.h e compilare il comando withgcc -include _declare_ver.h (anziché gcc). Se si utilizza make aggiungere

CFLAGS += -include _declare_ver.h 

nel vostro Makefile.

BTW, questo è un trucco sporco. Dovresti considerare di fare qualcosa di meglio (seguendo altre risposte).

Problemi correlati