Условная компиляция в Delphi, по сути, очень полезная и удобная возможность, которая позволяет Delphi компилировать или не компилировать код в зависимости от определенных символов условной компиляции. Говоря более простым языком (возможно и не совсем корректно), условная компиляция позволяет убрать или, наоборот, добавить часть кода исполняемого файла. Так или иначе, любой Delphi разработчик встречается с символами условной компиляции как минимум один раз за время работы над проектом.
Далее я рассмотрю различные примеры использования условной компиляции, которые могут Вам пригодиться в дальнейшей работе.
Для начала, рассмотрим очень простой код, который вы можете повторить в Delphi за несколько секунд:
procedure TForm2.FormCreate(Sender: TObject); begin {$IFDEF DEBUG} OutputDebugString(PChar('DEBUG IS ON!')); {$ENDIF} end;
Теперь нажмите F9 и проверьте, что написано в отладчике в «Events»:
Разберемся с тем, что мы только что написали.
Первая строка:
{$IFDEF DEBUG}
$IFDEF — это директива компилятора;
DEBUG — условное определение или символ условной компиляции. Символ обязательно должен начинаться с буквы за которой может следовать любое количество букв, цифр и знаков подчеркивания, однако использоваться будут лишь первые 255 символов.
Вторая строка:
OutputDebugString(PChar('DEBUG IS ON!'));
Процедура отправляет строку в отладчик для отображения.
Третья строка:
{$ENDIF}
Завершает условную компиляцию, инициированную последней директивой {$IFxxx} (почему не {$IFDEF} — смотрим далее).
Таким образом, используя директивы {$IFDEF} и {$ENDIF} мы указали компилятору дословно следующее: если где-либо по ходу компиляции был встречено условное определение DEBUG, то надо выполнить OutputDebugString.
Где определено условное определение DEBUG? Конкретно в этом случае, символ DEBUG можно найти, если зайти в настройки проекта: Project -> Options ->Delphi Compiler :
Здесь же можно определить и свои собственные символы. Давайте, например, добавим свой символ условной компиляции TEST. Для этого открываем диалоговое окно редактирования символов условной компиляции (жмем кнопку «…» в строке «Conditional defines») и заносим наш символ в список:
Теперь изменим наш код, приведенный в начале статьи, чтобы он работал с нашим символом условной компиляции:
procedure TForm2.FormCreate(Sender: TObject); begin {$IFDEF TEST} OutputDebugString(PChar('TEST IS ON!')); {$ENDIF} end;
Теперь можете снова запустить приложения в режиме отладки и посмотреть, что в Events появится строка «TEST IS ON».
Сейчас мы с вами рассмотрели самый простой способ использования условной компиляции в Delphi — использование директив {$IFDEF} и {$ENDIF}, а также определение собственного символа условной компиляции через свойства проекта. Вместе с этим, определить (включить) свой символ условной компиляции можно и в коде программы. Для этого используется директива компилятора {$DEFINE}. Воспользуемся этой директивой:
{$DEFINE MyTestSymbol} procedure TForm2.FormCreate(Sender: TObject); begin {$IFDEF MyTestSymbol} OutputDebugString(PChar('Символ MyTestSymbol определен')); {$ENDIF} end;
Соответственно, если есть директива определения нового символа, то должна быть и директива, которая отключает символы условной компиляции — она называется {$UNDEF}. Можете написать, например, вот такой код:
{$UNDEF DEBUG} procedure TForm2.FormCreate(Sender: TObject); begin {$IFDEF DEBUG} OutputDebugString(PChar('debug is on')); {$ENDIF} end;
и убедиться, что символ DEBUG выключен, а в окне Events не появится строка «debug is on».
Двигаемся далее. Что делать, если нам необходимо вывести строку не когда символ включен, а именно тогда, когда он выключен? Здесь, опять же, есть варианты. Короткий вариант — воспользоваться директивой противоположной {$IFDEF} — она называется {$IFNDEF} и код между {$IFNDEF} и {$ENDIF} выполняется, если символ выключен:
{Пример использования директивы IFNDEF} {$DEFINE MyTestSymbol} {$UNDEF DEBUG} procedure TForm2.FormCreate(Sender: TObject); begin {$IFNDEF DEBUG} //строка выведется в Events OutputDebugString(PChar('debug is off')); {$ENDIF} {$IFNDEF MyTestSymbol} //а эта строка - нет, т.к. символ MyTestSymbol включен OutputDebugString(PChar('MyTestSymbol is off')); {$ENDIF} end;
Второй вариант — использование директивы {$ELSE}, если в зависимости от состояния символа условной компиляции вам надо выполнять различные участки кода:
{$IFDEF DEBUG} //эта строка не выведется в Events, OutputDebugString(PChar('debug is ON')); {$ELSE} // а эта - выведется OutputDebugString(PChar('debug is OFF')); {$ENDIF}
Соответственно, нет необходимости далее повторять этот же участок кода с использованием {$IFNDEF} — работать будет, но прямо противоположно.
Также следует обратить внимание на то, что все условные символы оцениваются в Delphi, когда вы выполняете Build проекта. Справка Delphi рекомендует для надежности пользоваться командой Project -> Build All Projects, чтобы быть уверенным, что все символы условной компиляции определены верно.
В Delphi также определен набор символов условной компиляции, которые вы можете использовать при работе над своим проектом.
Например, символ условной компиляции VER330 определен для Delphi 10.3 Rio и с его помощью можно определить какой код должен или не должен выполняться, в случае, если версия компилятора Delphi — 33. Например, воспользуемся фичей Delphi 10.3 Rio под названием Inline Variable Declaration:
procedure TForm2.FormCreate(Sender: TObject); begin //этот код сработает только в Delphi 10.3 Rio {$IFDEF VER330} var s: string; S:='Inline Variable'; ShowMessage(S); {$ENDIF} end;
Сразу может возникнуть вопрос: как сделать так, чтобы приведенный выше код сработал не только в Delphi 10.3 Rio, но и в последующих версиях?
Это можно сделать воспользовавшись, например, такой конструкцией:
{$IF CompilerVersion >= 33.0} var s: string; S:='Inline Variable'; ShowMessage(S); {$IFEND}
Здесь мы уже воспользовались директивой {$IF} с помощью которой проверили значение константы CompilerVersion, которая находится в модуле System.
Здесь же стоит обратить внимание и на окончание блока — мы использовали директиву {$IFEND}, как того требовала Delphi до версии Delphi XE4:
- для директивы $IFDEF должна быть определена директива $ENDIF
- для директивы $IF должна быть определена директива $IFEND
В XE4 нам разрешили использовать {$ENDIF} для закрытия блоков {$IF}, {$IFDEF} и {$IFOPT}. Однако, если у вас возникают проблемы при использовании связки {$IF} и {$ENDIF}, то вы можете использовать специальную директиву {$LEGACYIFEND}, чтобы потребовать использовать для {$IF} именно {$IFEND}:
{$LEGACYIFEND ON} //закрываем IF по-старинке, используя IFEND {$IF CompilerVersion >= 33.0} {$IF Version=1} var s: string; S:='Inline Variable'; ShowMessage(S); {$ELSE} var d: TDateTime; d:=Now; ShowMessage('DateTime = '+DateTimeToStr(d)); {$IFEND} {$IFEND}
Теперь, если в коде выше использовать директиву $ENDIF, то получим сообщение об ошибке:
Директиву {$IF}, кстати, можно использовать и с другими константами проекта, например, так:
//определим собственную константу const Version = 2; procedure TForm2.FormCreate(Sender: TObject); begin //сначала проверяем версию компилятора {$IF CompilerVersion >= 33.0} {$IF Version=1} //теперь проверяем версию нашей программы var s: string; S:='Inline Variable'; ShowMessage(S); {$ELSE} //если версия программы не равна 1, то сработает код ниже var d: TDateTime; d:=Now; ShowMessage('DateTime = '+DateTimeToStr(d)); {$IFEND} {$IFEND} end;
Так как наша константа Version содержит значение 2, то выполнится участок кода расположенный после {$ELSE}. Можете сменить значение константы Version на 1, чтобы убедиться, что выполнится участок кода, где определена переменная s.
Как я сказал выше, в Delphi есть целый набор предопределенных символов условной компиляции. Ознакомиться со всеми этими символами вы можете на этой странице справки по Delphi.
Резюмируем.
- Использование условной компиляции позволяет нам выполнять тот или иной код, в зависимости от того, какие константы и символы условной компиляции определены или не определены в проекте.
- Используя предопредленные символы условной компиляции можно указывать Delphi какой код необходимо выполнить, например, если программа собирается под Android, или, если поддерживается архитектура x64 и т.д.
- Директива $IF может использоваться с различными константами, в том числе и определенными самим разработчиком.
При подготовке статьи использовалась следующая информация официальной справки по Delphi:
Книжная полка
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
||
Описание: Книга рассчитана на подготовленного пользователя ПК, желающего самостоятельно научиться программировать и разрабатывать приложения и базы данных в среде Delphi. Опытные программисты смогут использовать издание как справочник. В тексте подробно описаны более 80 компонентов VCL, функции Object Pascal и Win32 API.
|