Есть ли препроцессор C, который удаляет блоки #ifdef на основе определенных / неопределенных значений?

Исходный вопрос

Я бы хотел не стандартный препроцессор C, а его вариант, который принимал бы откуда-то - возможно, из командной строки через параметры -DNAME1 и -UNAME2 - спецификацию того, какие макросы определены, и затем исключил бы мертвые код.

Возможно, будет легче понять, что мне нужно, на нескольких примерах:

#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif

Если бы команда была запущена с '-DNAME1', результат был бы таким:

#define ALBUQUERQUE "ambidextrous"

Если бы команда была запущена с «-UNAME1», вывод был бы таким:

#define PHANTASMAGORIA "ghostly"

Если бы команда была запущена без опций, вывод был бы таким же, как ввод.

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

Чтобы проиллюстрировать это на реальном, но все же простом примере:

#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void    VOID;
#endif /* PLATFORM1 */
typedef void *  VOIDPTR;
#else
typedef mint     VOID;
typedef char *  VOIDPTR;
#endif /* USE_VOID */

Я хочу запустить команду с -DUSE_VOID -UPLATFORM1 и получить результат:

#undef VOID
typedef void    VOID;
typedef void *  VOIDPTR;

Другой пример:

#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */

В идеале я бы хотел запустить -UOLDUNIX и получить результат:

#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */

Возможно, мне повезло!

Мотивация: большая древняя кодовая база с большим количеством условного кода. Многие из условий больше не применяются - например, платформа OLDUNIX больше не производится и больше не поддерживается, поэтому нет необходимости содержать ссылки на нее в коде. Остальные условия всегда верны. Например, функции добавляются с помощью условной компиляции, так что одна версия кода может использоваться как для более старых версий программного обеспечения, где функция недоступна, так и для более новых версий, где она доступна (более или менее). В конце концов, старые версии без этой функции больше не поддерживаются - все использует эту функцию, поэтому условие о том, присутствует ли функция или нет, должно быть удалено, а также должен быть удален код «когда функция отсутствует». Я бы хотел иметь инструмент, который бы выполнял эту работу автоматически, потому что он будет быстрее и надежнее, чем делать это вручную (что весьма критично, когда база кода включает 21 500 исходных файлов).

(Действительно умная версия инструмента могла бы читать файлы #include'd, чтобы определить, определены ли в этих файлах управляющие макросы - те, которые указаны с помощью -D или -U в командной строке. Я не уверен, действительно ли это полезно, кроме в качестве резервной диагностики. Тем не менее, что бы он ни делал, псевдопрепроцессор не должен дословно расширять макросы или включать файлы. Выходные данные должны иметь исходный код, аналогичный, но обычно более простой, чем входной код.)

Отчет о состоянии (год спустя)

После года использования я очень доволен "sunifdef", рекомендованным выбранным ответом. Он еще не сделал ошибки, и я этого не ожидаю. Единственная придирка, которая у меня есть, - стилистическая. Учитывая ввод, например:

#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))

и запустить с '-UC' (C никогда не определяется), вывод будет:

#if defined(A) && defined(B) || defined(D) && defined(E)

Это технически правильно, потому что «&&» связывает более жестко, чем «||», но это открытое приглашение к путанице. Я бы предпочел, чтобы набор условий '&&' заключался в круглые скобки, как в оригинале:

#if (defined(A) && defined(B)) || (defined(D) && defined(E))

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


Новый ребенок в блоке

Проверив URL-адрес для включения в приведенную выше информацию, я вижу (как и предполагалось) есть новая программа под названием Coan то есть преемник sunifdef. Он доступен на SourceForge с января 2010 года. Я проверю его ... другие отчеты позже в этом году, или, может быть, в следующем году, или когда-нибудь, или никогда.


person Jonathan Leffler    schedule 08.02.2009    source источник
comment
Спасибо за предложение - нет, это не то, что мне нужно. Я знаю, как смотреть на то, что видит компилятор (на днях я провел несколько часов, просматривая 37 000 строк расширенного вывода, чтобы понять, почему что-то пошло не так). Я хочу, чтобы #include и другие строки остались, а макросы не раскрывались.   -  person Jonathan Leffler    schedule 08.02.2009


Ответы (5)


Я абсолютно ничего не знаю о C, но похоже, что вы ищете что-то вроде unifdef. Обратите внимание, что он не обновлялся с 2000 года, но есть преемник под названием Son of unifdef (sunifdef).

person Jörg W Mittag    schedule 08.02.2009
comment
Скачал оба. При портировании sunifdef на Solaris 10 возникли проблемы; Я передал эту информацию разработчику. Сейчас выглядит многообещающе, я решил проблемы. Спасибо. - person Jonathan Leffler; 08.02.2009
comment
sunifdef работает довольно хорошо - и выявляет доселе нереализованные глубины порочности в кодовой базе. Ну что ж; в конечном итоге он станет чище. Спасибо за наводку, Йорг. - person Jonathan Leffler; 10.02.2009
comment
Пожалуйста. Я любитель чистого, красивого, выразительного кода - я рад, что смог помочь вам сделать мир лучше :-) - person Jörg W Mittag; 10.02.2009
comment
Также обратите внимание на аналогичный вопрос здесь, что сейчас unifdef активно поддерживается и используется в ядре Linux. - person Shafik Yaghmour; 31.03.2014

Также вы можете попробовать этот инструмент http://coan2.sourceforge.net/

что-то вроде этого удалит блоки ifdef:

coan source -UYOUR_FLAG --filter c, h --recurse YourSourceTree

person ernesto    schedule 20.06.2013
comment
Добро пожаловать в Stack Overflow. Прочтите FAQ в ближайшее время. Коан упоминается в основном вопросе как «Новичок в блоке». - person Jonathan Leffler; 20.06.2013

Я использовал unifdef несколько лет назад для решения той проблемы, которую вы описываете, и она отлично сработала. Даже если он не обновлялся с 2000 года, синтаксис препроцессора ifdefs с тех пор существенно не изменился, поэтому я ожидаю, что он по-прежнему будет делать то, что вы хотите. Я предполагаю, что могут быть некоторые проблемы с компиляцией, хотя пакеты появляются недавно.

Я никогда не использовал sunifdef, поэтому не могу комментировать его напрямую.

person Dale Hagglund    schedule 08.02.2009

Примерно в 2004 году я написал инструмент, который сделал именно то, что вы ищете. Я так и не дошел до того, чтобы распространять инструмент, но код можно найти здесь:

http://casey.dnsalias.org/exifdef-0.2.zip (это dsl ссылка)

Это около 1,7 тыс. Строк и реализует достаточно грамматики C для синтаксического анализа инструкций препроцессора, комментариев и строк с использованием bison и flex.

person johnny    schedule 08.02.2009

Если вам нужно что-то похожее на препроцессор, гибкое решение - Wave (от буста). Это библиотека, предназначенная для создания инструментов, подобных препроцессору C (включая такие вещи, как препроцессоры C ++ 03 и C ++ 0x). Поскольку это библиотека, вы можете подключиться к ее входному и выходному коду.

person MSalters    schedule 10.02.2009
comment
Спасибо. Это выглядит интересно, но для работы требуется упаковка, тогда как sunifdef уже упакован и выполняет свою работу довольно хорошо. Я добавил URL - спасибо за информацию. - person Jonathan Leffler; 10.02.2009