2015-04-09 4 views
8

В наших исходных файлах мы обычно имеем строку версии так:предотвратить GCC от удаления неиспользуемой переменной

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

Когда эта строка не оптимизирована далеко, это очень полезно в некоторых случаях, как можно определить, версию каждого исходного файла, связанного с исполняемым файлом, просто вызывая strings a.out | grep VERSION.

К сожалению, это is оптимизировано прочь от gcc (используя '-O'). Поэтому мой вопрос заключается в том, есть ли простой способ (коммутатор компилятора был бы замечательным), чтобы gcc сохранил эту переменную (ее имя всегда одно и то же), не отключая других оптимизаций.

Редактировать

Что, на мой взгляд, делает вопрос, отличный от that one, что я был в надежде найти решение, для которого я бы не трогать тысячи исходных файлов.

+0

Как добавить опцию '-v' на все ваши двоичные файлы, отображающие этот var? –

+0

Может быть, попробуйте обмануть 'gcc', чтобы подумать, что используется переменная (что-то вроде' strlen (srcvers); ')? –

+3

Попытка сделать его «изменчивым»? Он должен работать: 'volatile static const char srcvers [] =" VERSION/foo.c/1.01/09.04.15 ";' –

ответ

17

Вы можете использовать __attribute__((used)) GCC (также работает в звоном) специфический (я вижу, что вопрос помечен gcc) атрибуты для этого:

Этот атрибут, к функции, означает, что код должен быть излучаемый для функции, даже если окажется, что функция не ссылается. Это полезно, например, когда функция ссылается только на встроенную сборку.

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

Демо:

$ 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 

Вы можете использовать некоторые #if с и #define с, чтобы сделать этот terser, а также компиляции на компиляторах, которые не поддерживают это расширение.

+2

Несмотря на то, что в выдержке документации описывается использование этого атрибута с функциями, один и тот же атрибут может также использоваться с переменными, если они имеют статическое хранилище (как в этом случае). –

+0

отличная идея, спасибо. Но идеальным решением было то, где мне не нужно было бы изменять каждый исходный файл. –

+0

@IngoLeonhardt - вы можете сделать что-то подобное с помощью сценария компоновщика. –

3

Объявление переменной как volatile также может помочь. Именно поэтому он используется в первую очередь, не позволяя компилятору оптимизировать эту переменную.

+0

Это определенно помогает; Я уже проверил. Но опять же, это означало бы трогать каждый файл :-(. Спасибо в любом случае –

+0

Обратите внимание, что это * реализация определена *. Нет гарантии, что это будет работать, поскольку стандарт требует, чтобы 'volatile' влиял на доступ к переменной. Если переменная никогда не используется, компилятор может удалить ее свободно. – user694733

4

Насколько я понимаю ваш вопрос, вам нужно добавить строку версии в каждый объектный файл, не касаясь источников. Это можно сделать следующим образом.

Создать файл заголовка, например 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 */ 

Затем в Makefile (или что-то ваша система сборки) добавить следующий gcc флаг:

CPPFLAGS += -include include/version.h 

Конечно, это должно быть передано gcc, напримеркак это:

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

Теперь вы можете наблюдать вашу _ver строка компилируется каждый объектный файл:

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

который покажет вам что-то вроде этого:

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

строка версии уже существует, но оптимизирована (и, конечно, мне нужна эта с датами типа '03 .01.01 ', некоторые файлы действительно старые). Но идея wih '-include' немного пахнет, как будто я мог использовать его для решения проблемы в любом случае. Еще раз спасибо –

+0

А, у вас есть исходные файлы, которые имеют разные версии. Думаю, что эта версия означает сам проект. –

+0

nope, что тоже будет (на самом деле это дополнительная информация, которую мы уже имеем, но иногда вам нужно быть уверенным, связано ли какое-то изменение в файле, включенном библиотекой ..) –

1

Как мне кажется, что все решения требуют какого-то украшения строки версии в источнике, это может помочь определить макрос, содержащий весь необходимый синтаксис, а затем использовать этот макрос в источнике или он Адер файлы всякий раз, когда необходимо:

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

Тогда в источнике просто положить

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

Макрос может быть в центральном заголовочном файле проекта или в командной строке компилятора.

Таким образом, по крайней мере, вам не придется прикоснуться ко всем исходным файлам, если вы хотите что-то изменить в определении.

Обратите внимание, как определение макроса использует конкатенацию строк для построения окончательной версии. Также он содержит конечную точку с запятой, поэтому вы можете удалить все, указав при необходимости пустой макрос.

0

Вы беспокоитесь об gcc удалении неиспользуемой переменной static char[]. AFAIK, компилятор прав на это.

Другие ответы предоставили предложение улучшить это. Но вы не хотите менять исходный код тысяч файлов.

Возможно, вы можете изменить свою сборку (например, Makefile), чтобы каждый такой исходный файл с использованием трюка (что немного неправильно, как описано здесь ...) изменить не нужно. Таким образом, вы можете invoke GCC конкретно. Вы хотите:

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

(это заявление, а не определение), которое должно быть скомпилировано раньше всего. Поместите строку выше в некоторый файл _declare_ver.h и скомпилируйте команду withgcc -include _declare_ver.h (вместо gcc). При использовании make добавить

CFLAGS += -include _declare_ver.h 

в вашем Makefile.

BTW, это грязный трюк. Вы должны подумать о том, чтобы сделать что-то лучше (следуя другим ответам).