web-dev-qa-db-fra.com

empêcher gcc de supprimer une variable non utilisée

Dans nos fichiers source, nous avons généralement une version de chaîne comme celle-ci:

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

Lorsque cette chaîne n'est pas optimisée, elle est très utile dans certains cas, car il est possible de déterminer la version de chaque fichier source lié à un exécutable en appelant simplement strings a.out | grep VERSION.

Malheureusement, il est optimisé par gcc (avec '-O'). Ma question est donc la suivante: existe-t-il un moyen simple (un commutateur de compilateur serait formidable) de faire en sorte que gcc conserve cette variable (son nom est toujours identique) sans désactiver aucune autre optimisation?.

Modifier

Ce qui, à mon avis, rend la question différente de celle-là , c’est que j’espérais trouver une solution pour laquelle je n’aurais pas à toucher à des milliers de fichiers source. 

12
Ingo Leonhardt

Vous pouvez utiliser les attributs __attribute__((used))gcc (fonctionne également dans clang) spécifiques (je vois que la question est étiquetée gcc) pour cela:

Cet attribut, attaché à une fonction, signifie que le code doit être émis pour la fonction même s'il apparaît que la fonction n'est pas référencée. Ceci est utile, par exemple, lorsque la fonction est référencée uniquement dans un assemblage en ligne.

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

Démo:

$ 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

Vous pouvez utiliser certains #ifs et #defines pour créer ce testeur et également compiler sur des compilateurs qui ne prennent pas en charge cette extension.

23
Dogbert

Si je comprends bien votre question, vous devez ajouter une chaîne de version à chaque fichier d’objet sans toucher aux sources. Cela peut être fait de la manière suivante.

Créez un fichier d'en-tête, par exemple 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 */

Puis dans votre Makefile (ou quel que soit votre système de construction), ajoutez le prochain indicateur gcc:

CPPFLAGS += -include include/version.h

Bien sûr, il devrait être passé à gcc, par exemple. comme ça:

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

Vous pouvez maintenant observer votre chaîne _ver compilée dans chaque fichier objet:

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

Ce qui va vous montrer quelque chose comme ça:

Disassembly of section .rodata._ver:
00000000 <_ver>:
5
Sam Protsenko

Comme il semble que toutes les solutions nécessitent une sorte de décoration de la chaîne de version dans le source, il peut être utile de définir une macro contenant toute la syntaxe nécessaire, puis d’utiliser cette macro dans les fichiers source ou en-tête à tout moment:

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

Ensuite, dans votre source, mettez simplement

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

La macro peut se trouver dans un fichier d'en-tête de projet central ou sur la ligne de commande du compilateur.

De cette façon, au moins vous n’aurez plus à toucher à tous les fichiers source si vous souhaitez modifier quelque chose à propos de la définition.

Notez que la définition de macro utilise la concaténation de chaînes pour créer la chaîne de version finale. Elle contient également le point-virgule final afin que vous puissiez tout supprimer en définissant une macro vide si nécessaire.

1
Ber

Déclarer la variable sous la forme volatile peut également aider. C'est pourquoi il est utilisé en premier lieu, empêchant le compilateur d'optimiser cette variable.

1
nikaltipar

Vous êtes préoccupé par le fait que gcc supprime une variable static char[] non utilisée. Autant que je sache, le compilateur a raison de le faire.

D'autres réponses ont suggéré de l'améliorer. Mais vous ne voulez pas changer le code source de milliers de fichiers.

Ensuite, vous pourriez peut-être modifier votre version (par exemple, une Makefile) afin que tout fichier source utilisant votre astuce (ce qui est légèrement faux, comme indiqué ici ...) n'ait pas besoin d'être modifié. Donc, vous pouvez invoquer GCC spécifiquement. Tu veux

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

(c'est une déclaration, pas une définition) à compiler avant toute chose. Placez la ligne ci-dessus dans un fichier _declare_ver.h et compilez avecgcc -include _declare_ver.h (au lieu de gcc). Si vous utilisez make, ajoutez

 CFLAGS += -include _declare_ver.h

dans votre Makefile.

BTW, c'est un sale tour. Vous devriez envisager de faire quelque chose de mieux (en suivant d'autres réponses).

0