Исходный вопрос
Я бы хотел не стандартный препроцессор 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 года. Я проверю его ... другие отчеты позже в этом году, или, может быть, в следующем году, или когда-нибудь, или никогда.