Можно ли условно компилировать / запускать код на основе макроса ИЛИ переменной? - PullRequest
3 голосов
/ 06 июля 2011

У нас есть несколько проектов в разработке, использующих одну и ту же кодовую базу. Определенные фрагменты кода относятся только к одному или другому из этих проектов.

У нас есть пара требований:

Первое требование состоит в том, что мы хотим, чтобы наши окончательные выпуски не компилировались в коде из других проектов.

Одним из решений (которое нам нравится) является использование препроцессора для удаления этого кода: (это то, что мы делаем в некоторых местах).

#if defined PROJECT1
{
    // some code
}
#endif

Второе требование заключается в том, что во время разработки полезно убедиться, что изменение кода по-прежнему работает во всех проектах, поэтому мы хотели бы скомпилировать ВСЕ код проекта сразу и иметь возможность переключаться между проекты без перекомпиляции - поэтому в других местах нашего кода мы используем переменную для определения проекта:

if (project == 1)
{
    // some code
}

Что я хотел бы сделать, так это объединить преимущества обоих - кода, который в некоторых ситуациях (скажем, определяется #define REMOVECODE) вообще не включается в финальный exe, но в других ситуациях (определяется не определением определения REMOVECODE) для включения кода в скомпилированный файл .exe

Еще одна вещь - иногда у нас есть код, который существует в нескольких проектах, поэтому решение должно обрабатывать такие тесты, как «if project == 1 || project == 2»

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

#ifdef REMOVECODE
    #define BEGINTEST #if
    #define ENDTEST   #endif
    #define CONDITION1 defined PROJECT1
#else
    #define BEGINTEST if
    #define ENDTEST
    #define CONDITION1 project == 1
#endif

BEGINTEST(CONDITION1)
{
    // some code
}
ENDTEST

Если кто-нибудь может помочь, я буду очень признателен.

Ответы [ 6 ]

4 голосов
/ 06 июля 2011

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

Так что что-то простое, как это должно работать нормально:

#ifdef REMOVECODE

#ifdef PROJECT1
#define CONDITION1 1
#else
#define CONDITION1 0
#endif

#else
#define CONDITION1 project == 1
#endif

...

if (CONDITION1)
{
    ...
}

Запустите ваш компилятор с -S (или эквивалентным) и посмотрите на сгенерированную сборку для подтверждения.

1 голос
/ 06 июля 2011

Как насчет другого определения, говорящего "построить все" А затем используйте

#if defined(PROJECT1) || defined(BUILDALL)
    ...
#endif

Или во избежание добавления || defined(BUILDALL) везде, где вы можете вставить это где-нибудь, где это будет видно:

#ifdef BUILDALL
    #define PROJECT1
    #define PROJECT2
    //...
#endif

Или просто скомпилировать все макросы проекта, определенные

1 голос
/ 06 июля 2011

не сработает;вы не можете генерировать «директивы препроцессора» из внутренних макросов и т. д.

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

Те же комментарии применимы к C и C ++:

ИСО / МЭК 14882: 1998 (стандарт С ++)

16.3.4 Повторное сканирование и дальнейшая замена [cpp.rescan]

The3 Результирующая полностью замененная макросом последовательность токена предварительной обработки не являетсяобрабатывается как директива предварительной обработки, даже если она похожа на одну.

ISO / IEC 9899: 1999 (стандарт C)

6.10.3.4 Повторное сканирование и дальнейшая замена

¶3 Результирующая последовательность токенов предварительной обработки, полностью замененная макросами, не обрабатывается как директива предварительной обработки, даже если она похожа на одну, ...

(В многоточии упоминается C99 _Pragma особенность.)

0 голосов
/ 06 июля 2011

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

#define HARD_P1
#define SOFT_P1

Тогда

#ifdef HARD_P1
#define P1
#ifdef SOFT_P1
#define USEP1
#else
#define USEP1 /##/
#endif
#endif

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

Код

#ifdef P1
void test()
{
USEP1 if(project==1)
    {
    }
}
#endif
0 голосов
/ 06 июля 2011

Рефакторинг вашего дизайна. Разбейте код на небольшие независимые библиотеки. Только ссылка в том, что вам нужно для каждого проекта. В противном случае вы получите очень сложный беспорядок.

0 голосов
/ 06 июля 2011

А что плохого в том, что у нас есть автоматическое управление ночью, которое перестраивает все проекты и запускает набор автоматических тестов для каждого из них, и вы узнаете, что что-то не так?

То, что я вижу здесь, скорее всего закончится#ifdef clusterfuck или дополнительная сложность кода + ошибки ни за что.

...