$DefinitionInfo — Директива компилятора Delphi

Содержание

Директивы компилятора — Версии Delphi

У меня есть блок, который я написал в Delphi 7 некоторое время назад, и просто получил удовольствие (боль) от преобразования в Delphi XE (Unicode).

Устройства работают отлично после некоторых проблем, теперь я пытаюсь сделать этот модуль совместимым с разными версиями Delphi, если мне когда-либо понадобится переключить IDE обратно в Delphi 7, обновляя какой-то другой код.

У меня только Delphi 7 и Delphi XE, но из того, что я собираю, код, написанный в Delphi 1, Delphi 2007 будет компилироваться, но код из Delphi 2009 и выше будет Unicode.

. В любом случае, в модуле я разделяю un-unicode и unicode так:

Как изменить директиву компилятора, чтобы правила применялись к нескольким версиям? Например, что-то вроде:

Затем это будет охватывать все версии Delphi, если я буду распространять источник или блок .dcu.

Интересно, является ли самый простой подход в этом случае переключать поведение на UNICODE условном. Это условие определено тогда и только тогда, когда вы используете Unicode-версию Delphi, то есть в Delphi 2009 и более поздних версиях. Большим преимуществом этого является то, что это будущее доказательство — вам не нужно обновлять свой код каждый раз, когда выпускается новый Delphi. Более того, условный переключатель будет гораздо читабельнее, поскольку он четко выражает намерение.

В документации Delphi есть отличная тема, в которой перечислены все заранее определенные условные обозначения. Полный список условных обозначений версий также связан.

Директивы по версиям компилятора Delphi: <$ IFDEF VER180>— 2020

Подготовка к кодированию без барьеров. Узнайте, как преодолеть проблему с версией компилятора: компиляция кода Delphi для различных версий Delphi.

Если вы планируете писать код Delphi, который должен работать с несколькими версиями компилятора Delphi, вам необходимо знать, в каких версиях компилируется ваш код.

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

Если они попытаются перекомпилировать код компонента (ваш код) — у них могут быть проблемы! Что если вы использовали параметры по умолчанию в ваших функциях, а у пользователя Delphi 3?

Директива компилятора: $ IfDef

Директивы компилятора — это специальные синтаксические комментарии, которые мы можем использовать для управления функциями компилятора Delphi. Компилятор Delphi имеет три типа директив: переключение директив, директивы параметров а также условные директивы, Условная компиляция позволяет нам выборочно компилировать части исходного кода в зависимости от того, какие условия установлены.

Директива компилятора $ IfDef запускает секцию условной компиляции.

Синтаксис выглядит так:

DefName представляет так называемый условный символ. Delphi определяет несколько стандартных условных символов. В приведенном выше «коде», если определено DefName, код выше $ Else компилируется.

Delphi Version Symbols

Распространенным применением директивы $ IfDef является тестирование версии компилятора Delphi.

В следующем списке указаны символы, которые необходимо проверить при условной компиляции для конкретной версии компилятора Delphi:

  • УСЛОВНОЕ ОБОЗНАЧЕНИЕ — Компиляционная версия
  • VER80 — Delphi 1
  • VER90 — Delphi 2
  • VER100 — Delphi 3
  • VER120 — Delphi 4
  • VER130 — Delphi 5
  • VER140 — Delphi 6
  • VER150 — Delphi 7
  • VER160 — Delphi 8
  • VER170 — Delphi 2005
  • VER180 — Delphi 2006
  • VER180 — Delphi 2007
  • VER185 — Delphi 2007
  • VER200 — Delphi 2009
  • VER210 — Delphi 2010
  • VER220 — Delphi XE
  • VER230 — Delphi XE2
  • WIN32 — Указывает, что операционной средой является Win32 API.
  • LINUX — Указывает, что операционной средой является Linux
  • MSWindows — Указывает, что операционной средой является MS Windows / li]
  • ПРИСТАВКА — Указывает, что приложение компилируется как консольное приложение.

Зная вышеупомянутые символы, можно написать код, который работает с несколькими версиями Delphi, используя директивы компилятора для компиляции соответствующего исходного кода для каждой версии.

Примечание: символ VER185, например, используется для обозначения компилятора Delphi 2007 или более ранней версии.

Использование символов «VER»

Обычно (и желательно) для каждой новой версии Delphi добавлять несколько новых подпрограмм RTL к языку.

Например, функция IncludeTrailingBackslash, представленная в Delphi 5, добавляет «» в конец строки, если ее там еще нет. В проекте Delphi MP3 я использовал эту функцию, и несколько читателей пожаловались, что не могут скомпилировать проект — у них есть какая-то версия Delphi до Delphi 5.

Одним из способов решения этой проблемы является создание собственной версии этой подпрограммы — функции AddLastBackSlash.

Если проект должен быть скомпилирован на Delphi 5, вызывается IncludeTrailingBackslash. Если используются некоторые из предыдущих версий Delphi, мы моделируем функцию IncludeTrailingBackslash.

Это может выглядеть примерно так:

функция AddLastBackSlash (ул: строка) : строка; начать Результат: = IncludeTrailingBackslash (str); если Copy (str, Length (str), 1) = «» затем Результат: = ул еще Результат: = str + «»; конец;

При вызове функции AddLastBackSlash Delphi выясняет, какая часть функции должна использоваться, а другая часть просто пропускается.

Delphi 2008?

Delphi 2007 использует VER180 для обеспечения неразрывной совместимости с Delphi 2006, а затем добавляет VER185 для разработки, которая по каким-либо причинам должна быть нацелена на Delphi 2007.

Примечание. Каждый раз, когда интерфейс модуля изменяет код, использующий этот модуль, его необходимо перекомпилировать.Delphi 2007 — выпуск без прерываний, означающий, что файлы DCU из Delphi 2006 будут работать как есть.

Директивы компилятора — Delphi версии

У меня есть блок, который я написал в Delphi 7 некоторое время назад, и только было весело (боль) преобразования в Delphi XE (Unicode).

Группа работает отлично после того, как некоторые проблемы, я сейчас пытаюсь сделать это устройство совместимо с различными версиями Delphi я должен когда-нибудь понадобится, чтобы переключиться обратно в IDE Delphi 7 в то время как обновление какой-либо другой код.

У меня только Delphi 7 и Delphi XE, но от того, что я собираю код, написанный на Delphi 1 в Delphi 2007 будет компилировать, но код с Delphi 2009 и выше будет Unicode.

. Во всяком случае, в блоке я отделяя не-Юникод и Юникод, как так:

Как изменить директиву компилятора поэтому правила применяются к Многоязычным версиям? Например, что-то вроде:

Это позволило бы охватить все версии Delphi я должен распространять исходный или .dcu блок.

Интересно , если самый простой подход в данном случае является переключение поведения на UNICODE условный. Это условное определяется тогда и только тогда , когда вы используете версию Unicode в Delphi, то есть в Delphi 2009 и более поздних версий. Большим преимуществом является то , что это будущее доказательство вам не нужно обновить код каждый раз , когда новый Delphi отпускается. Более того, условный переключатель будет гораздо более удобным для чтения , так как он будет четко выражать намерение.

Документация Delphi имеет отличную тему со списком всех предварительно определенными условными. Полный список версии условных также связан оттуда.

Директивы компилятора

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

Давайте для примера рассмотрим несколько наиболее широко используемых директив компилятора.

Директива trace применяется при отладке программы для трассирования. Этот процесс немного похож на пошаговое выполнение императивной программы с отслеживанием значений переменных. Трассировка позволяет пользователю наблюдать за ходом выполнения программы. Если после ключевого слова trace указаны имена предикатов через запятую, то трассировка идет только по этим предикатам. В противном случае — по всем предикатам программы. После завершения отладки трассировку нужно выключить, чтобы компилятор мог осуществить оптимизацию хвостовой рекурсии, о которой рассказывалось в предыдущей лекции.

Во время исполнения программы при включенной трассировке в специальном окне трассировки будет отображаться следующая информация:

после слова «CALL» будет указано имя выполняемого предиката (текущая подцель) и его параметры; *

после слова «FAIL» будет выводиться имя текущей подцели, которая не была достигнута;

после слова «RETURN» будет выводиться результат вычисления текущей подцели, в случае успеха. При этом если у подцели есть еще альтернативы, к которым возможен возврат, то перед именем предиката высвечивается звездочка («*»);

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

Переход от подцели к подцели вызывается нажатием функциональной клавиши F10. При этом в окне редактирования выполняющуюся подцель указывает курсор, она также отображается в окне трассировки с параметрами и дополнительной информацией.

Директива nowarnings используется для подавления предупреждения системы о том, что какая-то переменная встречается в предложении только один раз. Эту директиву стоит использовать только в хорошо отлаженных программах. Как правило, для подавления такого предупреждения («WARNING: The variable is only used once») достаточно заменить переменную, которая встретилась только один раз, на анонимную переменную.

С помощью директивы include при компиляции в исходный текст можно вставить содержимое некоторого файла.

Заметим, что многие директивы компилятора могут быть не только расположены в тексте программы, но и установлены в меню среды разработки Турбо Пролога (Options Compiler Directives). Значение директивы компилятора, указанное в тексте программы, имеет более высокий приоритет, чем значение, установленное в меню.

Раздел описания констант

Раздел, озаглавленный зарезервированным словом CONSTANTS, предназначен для описания констант. Объявление константы имеет вид:

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

Каждое определение константы должно размещаться в отдельной строке.

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

Разделов описания констант может быть несколько, но каждая константа должна быть определена до ее первого использования.

Раздел описания доменов

Раздел описания доменов является аналогом раздела описания типов в обычных императивных языках программирования и начинается с ключевого слова DOMAINS.

В Турбо Прологе имеются стандартные домены, которые не нужно указывать в разделе описания доменов. Основные стандартные домены — это:

integer — целое число (из промежутка -32768. 32767);

real — действительное число (лежащее между ±1e-307. ±1e308);

char — символ, заключенный в одиночные апострофы;

string — последовательность символов, заключенная в двойные кавычки;

symbol — символическая константа (начинающаяся со строчной буквы последовательность букв латинского алфавита, цифр и знаков подчеркивания или последовательность любых символов, заключенная в кавычки). Этот домен соответствует понятию атома, с которым мы познакомились во второй лекции;

file — файл (подробному изучению файлов будет посвящена лекция 12).

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

Объявление домена имеет следующий вид:

Удобно использовать описание доменов для сокращения имен стандартных доменов. Например, чтобы не писать каждый раз integer, можно написать следующее:

и далее использовать вместо ключевого слова integer односимвольное обозначение i.

Из доменов можно конструировать составные или структурные домены (структуры). Структура описывается следующим образом:

Каждая компонента структуры в свою очередь может быть структурой. Например, структура, описывающая точку на плоскости и имеющая две компоненты (координаты точки)

point = p(integer, integer)

может входить в качестве компоненты в более сложную структуру, описывающую треугольник:

triangle = tr(point, point, point)

В описание структуры могут входить альтернативы, разделенные символом «;» или ключевым словом «or».

Так, структуру, описывающую точку и на плоскости, и в пространстве, можно задать следующим образом:

point = p(integer, integer);p(integer, integer, integer).

Описание файлового домена имеет вид:

Для представления данных в Турбо Прологе, в отличие от стандартных алгоритмических языков программирования, используются не массивы, а списки. Подробнее списки будут рассмотрены в следующей лекции, а пока заметим, что списковый домен задается следующим образом:

Например, список целых чисел описывается так:

Раздел описания предикатов внутренней базы данных

Работа с внутренними (динамическими) базами данных в Прологе будет рассмотрена в лекции 13. Начинается раздел описания предикатов внутренней базы данных с зарезервированного слова DATABASE и описываются в нем те предикаты, которые можно в процессе выполнения программы добавлять во внутреннюю базу данных или удалять оттуда. Описываются предикаты базы данных аналогично предикатам в разделе описания предикатов PREDICATES, который мы сейчас рассмотрим.

Раздел описания предикатов

В разделе, озаглавленном зарезервированным словом PREDICATES, содержатся описания определяемых пользователем предикатов. В традиционных языках программирования подобными разделами являются разделы описания заголовков процедур и функций. Описание n-местного предиката имеет следующий вид:

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

Например, предикат, описывающий отношение «мама», которым мы пользовались в третьей лекции, может быть описан следующим образом:

Это описание означает, что у предиката два аргумента, причем оба строкового типа.

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

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

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

Для того чтобы указать, что предикат является детерминированным (недетерминированным), нужно перед его именем поместить зарезервированное слово determ (nondeterm). Если ни determ, ни nondeterm при описании предиката не использовались, то, по умолчанию, предикат считается детерминированным.

В Турбо Прологе имеется директива компилятора check_determ, которая принудительно включает проверку предикатов на детерминированность.

В Турбо Прологе есть так называемые стандартные (встроенные) предикаты, которые не нужно описывать в разделе описания предикатов PREDICATES. Наиболее употребляемые из них мы рассмотрим чуть позже. Все встроенные предикаты являются детерминированными.

Раздел описания предложений Этот раздел можно считать основным разделом программы, потому что именно в нем содержатся факты и правила, реализующие пользовательские предикаты. Все предикаты, которые применяются в этом разделе и не являются стандартными предикатами, должны быть описаны в разделе описания предикатов или в разделе описания предикатов базы данных. Начинается этот раздел со служебного слова CLAUSES. Напомним, что предложения, у которых в заголовке указан один и тот же предикат, должны идти друг за другом. Такой набор предложений называется процедурой. Предложения довольно подробно обсуждались в третьей лекции, поэтому сейчас мы не будем подробно останавливаться на этом. Заметим только, что программу на Прологе принято оформлять по следующим правилам: между процедурами пропускается пустая строка; тело правила записывается со следующей строки, после строки, в которой был заголовок, с отступом; каждую подцель записывают на отдельной строке, одну под другой. Эти правила не являются обязательными, но они делают программу более «читабельной». Раздел описания внутренней цели С зарезервированного слова GOAL начинается раздел описания внутренней цели программы. Если этот раздел отсутствует, то после запуска программы Пролог-система выдает приглашение вводить вопросы в диалоговом режиме (внешняя цель). При выполнении внешней цели Пролог-система ищет все решения, выводя все возможные значения для переменных, участвующих в вопросе. Если же выполняется внутренняя цель, то осуществляется поиск только первого решения, а для получения всех решений нужно предпринимать дополнительные действия. Программа, компилируемая в исполняемый файл, который можно запускать независимо от среды разработки, обязательно должна иметь внутреннюю цель. Внешнюю цель обычно применяют на этапе отладки программы. Внешние и внутренние цели уже обсуждались в третьей лекции, они еще будут рассматриваться в следующей лекции, поэтому сейчас мы не будем останавливаться на этом вопросе более подробно. Пример. Запишем полностью реализацию на Турбо Прологе той базы знаний про мам и бабушек, которую мы рассматривали в качестве примера в третьей лекции. Нажимаем комбинацию клавиш Alt+E (от Editor), попадаем в редактор. Набираем код, приведенный ниже. DOMAINS /* раздел описания доменов */ s=string /* вводим синоним для строкового типа данных */ PREDICATES /* раздел описания предикатов */ mother(s,s) /* предикат мама будет иметь два аргумента строкового типа */ grandmother(s,s) /* то же имеет место и для предиката бабушка */ CLAUSES /* раздел описания предложений */ mother(«Наташа»,»Даша»). /* «Наташа» и «Даша» связаны отношением мама */ mother(«Даша»,»Маша»). /* «Даша» и «Маша» также принадлежат отношению мама */ grandmother(X,Y):- /* X является бабушкой Y, если найдется такой Z, что */ mother(X,Z), /* X является мамой Z, а */ mother(Z,Y). /* Z является мамой Y */ Для запуска программы нажимаем Alt+R (Run). Так как раздела описания внутренней цели в нашей программе не было, Пролог система выведет приглашение на ввод внешней цели («GOAL:»). Вводим вопросы, наблюдаем результаты. Повтор предыдущей цели F8. Теперь давайте рассмотрим некоторые наиболее употребляемые стандартные предикаты. Начнем с предикатов, предназначенных для вывода и ввода. Предикаты ввода-вывода Турбо Пролог имеет отдельные предикаты для чтения с клавиатуры или из файла данных целого, вещественного, символьного и строкового типа. Работе с файлами будет посвящена лекция 12, а сейчас мы рассмотрим чтение из стандартного устройства ввода информации (клавиатуры) и, соответственно, запись на стандартное устройство вывода информации (монитор). Предикат readln считывает строку с текущего устройства ввода и связывает ее со своим единственным выходным параметром. Предикат readint читает с текущего устройства целое число и связывает его со своим единственным выходным параметром. Предикат readreal отличается от предиката readint тем, что он считывает не целое, а вещественное число. Для чтения символа с текущего устройства ввода используется предикат readchar. Есть еще предикат inkey, который так же, как и readchar, читает символ со стандартного устройства ввода. Разница между ними в том, что предикат readchar приостанавливает работу программы до тех пор, пока не будет введен символ, а предикат inkey не прерывает выполнение программы. Если нужно просто проверить, нажата ли клавиша, можно воспользоваться предикатом keypressed, не имеющим аргументов. Предикат readterm предназначен для чтения сложных термов. У него два параметра: первый входной указывает имя домена, второй параметр конкретизируется термом домена, записанного в первом параметре. Если считанная этим предикатом строка не соответствует домену, указанному в его первом параметре, предикат выдаст сообщение об ошибке. Для записи данных в текущее устройство записи служит предикат write. Он может иметь произвольное количество параметров. Кроме того, в Турбо Прологе есть еще и предикат writef, который служит для форматного вывода данных. Для осуществления перехода на следующую строку (возврат каретки и перевод строки) применяется предикат nl, не имеющий параметров. Описанная ниже группа предикатов служит для преобразования типов. Предикат upper_lower имеет два аргумента и три варианта использования. Если в качестве первого аргумента указана строка (или символ), а второй аргумент свободен, то второй аргумент будет означен строкой (символом), полученной из первого аргумента преобразованием к нижнему регистру. Если в исходной строке были прописные английские буквы, то они будут заменены строчными. Если же, наоборот, первый аргумент свободен, а второй аргумент — это строка (или символ), то первый аргумент получит значение, равное строке (символу), полученной из второго аргумента преобразованием к верхнему регистру. Если в строке, находящейся во втором аргументе, были строчные английские буквы, то они будут заменены прописными. И, наконец, имеется третий вариант использования. Если и первый, и второй аргументы связаны, то предикат будет истинным только в том случае, если во втором аргументе находится строка (символ), которая получается из строки, находящейся в первом аргументе, путем замены всех прописных английских букв на строчные. В противном случае предикат будет ложным. Также имеют два параметра и три варианта использования предикаты str_int, str_real. Первый преобразует строку в целое число и наоборот. Второй служит для превращения строки в вещественное число или вещественного числа в строку. Предикат str_char имеет те же параметры использования и применяется для преобразования односимвольной строки в один символ и наоборот. Немного по-другому работает предикат char_int. Он позволяет переходить от символа к его ASCII-коду и обратно. Хотя Пролог — не самый лучший инструмент для выполнения большого объема вычислений, в нем имеются стандартные средства для реализации обычных вычислений. При этом можно использовать четыре арифметических операции (сложение (+), вычитание (-), умножение (*) и деление (/)), а также целочисленное деление (div) и взятие остатка от деления одного целого числа на другое (mod). Для сравнения чисел можно воспользоваться операциями равно (=), не равно (<>), больше (>), больше или равно (>=), меньше (

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Увлечёшься девушкой-вырастут хвосты, займёшься учебой-вырастут рога 9790 — | 7665 — или читать все.

Директивы Компилятора-Версии Delphi

у меня есть единица, которую я написал в Delphi 7 некоторое время назад, и только что получил удовольствие (боль) от преобразования в Delphi XE (Unicode).

устройство отлично работает после некоторых проблем, теперь я пытаюсь сделать это устройство совместимым с различными версиями Delphi, если мне когда-либо понадобится переключить IDE обратно на Delphi 7 при обновлении другого кода.

У меня есть только Delphi 7 и Delphi XE, но из того, что я собираю код, написанный на Delphi 1 в Delphi 2007, будет компилироваться, но код из Delphi 2009 и выше будет Unicode.

. Во всяком случае, в блоке я разделяю не-unicode и unicode следующим образом:

Как изменить директиву компилятора, чтобы правила применялись к нескольким версиям? Например что-то вроде:

это будет охватывать все версии Delphi, если я распространю источник или .блок УЗК.

2 ответов

интересно, Самый простой подход в этом случае-переключить поведение на UNICODE условное. Это условие определяется тогда и только тогда, когда вы используете версию Delphi в Юникоде, т. е. в Delphi 2009 и более поздних версиях. Большим преимуществом этого является то, что это будущее-вам не нужно обновлять код каждый раз, когда выходит новый Делфи. Более того, условный переключатель будет гораздо более читаемым, поскольку он будет четко выражать намерение.

Delphi документация имеет отличный темы список всех предопределенных условий. Полный список условий версии также связан оттуда.

Условная компиляция в Delphi

Условная компиляция в Delphi, по сути, очень полезная и удобная возможность, которая позволяет Delphi компилировать или не компилировать код в зависимости от определенных символов условной компиляции. Говоря более простым языком (возможно и не совсем корректно), условная компиляция позволяет убрать или, наоборот, добавить часть кода исполняемого файла. Так или иначе, любой Delphi разработчик встречается с символами условной компиляции как минимум один раз за время работы над проектом.

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

Для начала, рассмотрим очень простой код, который вы можете повторить в Delphi за несколько секунд:

Теперь нажмите F9 и проверьте, что написано в отладчике в «Events»:

Разберемся с тем, что мы только что написали.

$IFDEF — это директива компилятора;

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

Процедура отправляет строку в отладчик для отображения.

Завершает условную компиляцию, инициированную последней директивой <$IFxxx>(почему не <$IFDEF>— смотрим далее).

Таким образом, используя директивы и мы указали компилятору дословно следующее: если где-либо по ходу компиляции был встречено условное определение DEBUG, то надо выполнить OutputDebugString.

Где определено условное определение DEBUG? Конкретно в этом случае, символ DEBUG можно найти, если зайти в настройки проекта: Project -> Options ->Delphi Compiler :

Здесь же можно определить и свои собственные символы. Давайте, например, добавим свой символ условной компиляции TEST. Для этого открываем диалоговое окно редактирования символов условной компиляции (жмем кнопку «…» в строке «Conditional defines») и заносим наш символ в список:

Теперь изменим наш код, приведенный в начале статьи, чтобы он работал с нашим символом условной компиляции:

Теперь можете снова запустить приложения в режиме отладки и посмотреть, что в Events появится строка «TEST IS ON».

Сейчас мы с вами рассмотрели самый простой способ использования условной компиляции в Delphi — использование директив и , а также определение собственного символа условной компиляции через свойства проекта. Вместе с этим, определить (включить) свой символ условной компиляции можно и в коде программы. Для этого используется директива компилятора . Воспользуемся этой директивой:

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

и убедиться, что символ DEBUG выключен, а в окне Events не появится строка «debug is on».

Двигаемся далее. Что делать, если нам необходимо вывести строку не когда символ включен, а именно тогда, когда он выключен? Здесь, опять же, есть варианты. Короткий вариант — воспользоваться директивой противоположной — она называется и код между и выполняется, если символ выключен:

Второй вариант — использование директивы , если в зависимости от состояния символа условной компиляции вам надо выполнять различные участки кода:

Соответственно, нет необходимости далее повторять этот же участок кода с использованием — работать будет, но прямо противоположно.

Также следует обратить внимание на то, что все условные символы оцениваются в Delphi, когда вы выполняете Build проекта. Справка Delphi рекомендует для надежности пользоваться командой Project -> Build All Projects, чтобы быть уверенным, что все символы условной компиляции определены верно.

В Delphi также определен набор символов условной компиляции, которые вы можете использовать при работе над своим проектом.

Например, символ условной компиляции VER330 определен для Delphi 10.3 Rio и с его помощью можно определить какой код должен или не должен выполняться, в случае, если версия компилятора Delphi — 33. Например, воспользуемся фичей Delphi 10.3 Rio под названием Inline Variable Declaration:

Сразу может возникнуть вопрос: как сделать так, чтобы приведенный выше код сработал не только в Delphi 10.3 Rio, но и в последующих версиях?
Это можно сделать воспользовавшись, например, такой конструкцией:

Здесь мы уже воспользовались директивой с помощью которой проверили значение константы CompilerVersion, которая находится в модуле System.

Здесь же стоит обратить внимание и на окончание блока — мы использовали директиву , как того требовала Delphi до версии Delphi XE4:

  • для директивы $IFDEF должна быть определена директива $ENDIF
  • для директивы $IF должна быть определена директива $IFEND

В XE4 нам разрешили использовать для закрытия блоков <$IF>, и . Однако, если у вас возникают проблемы при использовании связки и , то вы можете использовать специальную директиву , чтобы потребовать использовать для именно <$IFEND>:

Теперь, если в коде выше использовать директиву $ENDIF, то получим сообщение об ошибке:

Директиву , кстати, можно использовать и с другими константами проекта, например, так:

Так как наша константа Version содержит значение 2, то выполнится участок кода расположенный после . Можете сменить значение константы Version на 1, чтобы убедиться, что выполнится участок кода, где определена переменная s.

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

  1. Использование условной компиляции позволяет нам выполнять тот или иной код, в зависимости от того, какие константы и символы условной компиляции определены или не определены в проекте.
  2. Используя предопредленные символы условной компиляции можно указывать Delphi какой код необходимо выполнить, например, если программа собирается под Android, или, если поддерживается архитектура x64 и т.д.
  3. Директива $IF может использоваться с различными константами, в том числе и определенными самим разработчиком.

При подготовке статьи использовалась следующая информация официальной справки по Delphi:

Блог GunSmoker-а

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

19 апреля 2009 г.

Настройки проектов в Delphi с точки зрения поиска ошибок

О чём идёт речь

Сначала, давайте посмотрим на них: открываем Project/Options. Нас будут интересовать вкладки Compiling и Linking (в старых версиях Delphi они назывались Compiler и Linker):

На вкладке «Compiler» нас будут интересовать опции «Stack Frames», группа «Debug information», «Local Symbols» и «Symbol reference info», «I/O Checking», «Overflow checking» и «Range checking». На «Linking» — «Map file», «Debug Information» (известная в предыдущих версиях Delphi как «Include TD32 debug info») и «Include remote debug symbols».

Давайте посмотрим, за что отвечают эти опции. А затем — как их лучше бы всего расставить. При этом мы будем рассматривать такие ситуации: обычное приложение и приложение с механизмом диагностики исключений.
Кроме того, настройки проекта могут отличаться, компилируете ли вы приложение для себя или для распространения. В новых версиях Delphi появились профили настроек (Debug и Release, соответственно). Вы можете задать свой набор настроек в каждом профиле, а затем переключаться между ними. В старых Delphi есть только один профиль настроек и вам нужно менять каждую настройку вручную.

Напомним, что при смене любой из опций необходимо сделать полный Build проекту (а не просто Compile).

Что означают эти опции?

Самыми важными настройками являются группа опций «Debug information», «Local Symbols» и «Symbol reference info».

Программа представляет собой набор машинных команд. Текст программы представляет собой текстовый файл. Вопрос: как отладчик узнаёт, когда надо остановиться, если вы поставили бряк на строку в тексте? Где же соответствие между текстовым файлом и набором байт в exe-файле? Вот для такой связи и служит отладочная информация. Это, грубо говоря, набор инструкций типа: «машинные коды с 1056 по 1059 относятся к строке 234 модуля Unit1.pas». Вот с помощью такой информации и работает отладчик. Указанные выше опции отвечают за генерацию отладочной информации для ваших модулей.

Отладочная информация сохраняется вместе с кодом модуля в dcu-файле. Т.е. один и тот же Unit1.pas может быть скомпилирован как с отладочной информацией, так и без неё — в разные dcu файлы. Отладочная информация увеличивает время компиляции, размер dcu-файлов, но не влияет на размер и скорость работы полученного exe-файла (т.е. отладочная информация не подключается к exe-файлу) (*).

Бывают ситуации, когда наличие отладочной информации в файле или (хотя бы) рядом с файлом является необходимым. Например, если вы выполняете удалённую отладку или отладку внешнего процесса. Или если вам нужен читаемый стек вызовов в вашем средстве диагностики исключений.

Подключение отладочной информации к приложению осуществляется несколькими способами: либо это опции проекта (а именно: «Map File», «Debug information» (Linker)/«Include TD32 Debug info» или «Include remote debug symbols»), либо это возможности всевозможных экспертов (типа EurekaLog, JCL или madExcept), которые добавляют отладочную информацию в программу в своём формате.

Итак, опции отладочной информации:

  • «Debug information» (директива <$D+>или <$D->) – это собственно и есть отладочная информация. Т.е. соответствие между текстом программы и её машинным кодом. Вы должны включить эту опцию, если хотите ставить бряки, выполнять пошаговую отладку, а также иметь стек с именами для своего кода. Часто эту опцию включают автоматически различные эксперты типа EurekaLog.
  • «Local symbols» (директива <$L+>или <$L->) – является дополнением к отладочной информации. Она отвечает за соответствие между данными в exe-файле и именами переменных. Если вы включаете эту опцию, то отладчик позволит вам просматривать и изменять переменные. Также окно «Call Stack» будет способно отражать переданные в процедуры параметры.
  • «Reference info» – это дополнительная информация для редактора кода, которая позволяет ему отображать более подробную информацию об идентификаторах. Например, где была объявлена переменная.

Эти три опции тесно связаны и обычно нет смысла включать/выключать их по одной.

  • «Use Debug DCUs» — эта опция переключает сборку вашей программы с отладочными модулями Delphi или с обычными. Если вы внимательно посмотрите на установку Delphi, то увидите, что pas файлы из папки Source никогда не используются для компиляции — а только для отладки. Для компиляции же используются уже готовые dcu-файлы из папки Lib. Это уменьшает время компиляции. Поскольку dcu могут быть скомпилированы с отладочной информацией и без неё, то в папке Lib есть два набора dcu-файлов: обычные и отладочные. Переключая эту опцию, вы указываете, какие из них использовать. Если вы выключите эту опцию, то не сможете заходить по F7 в стандартные функции и методы Delphi (т.к. для них будет отсутствовать отладочная информация). Также при выключенной опции вы не будете видеть информацию о стандартном коде в стеке вызовов.
  • «Stack Frames» — эта опция отвечает за генерацию стековых фреймов. Если опция выключена, то стековый фрейм не генерируется без необходимости. Если она включена -то фрейм генерируется всегда. Стековые фреймы используются при построении стека вызовов по фреймам (построение методом raw-сканирование не нуждается в стековых фреймах). В обычном приложении стековые фреймы генерируются практически всегда (**).
  • «Range checking» — служит помощником в поиске проблем при работе, например, с массивами. Если её включить, то для любого кода, который работает с массивами и строками, компилятор добавляет проверочный код, который следит за правильностью индексов. Если при проверке обнаруживается, что вы вылезаете за границы массива, то будет сгенерировано исключение класса ERangeError. При этом вы можете идентифицировать ошибку обычной отладкой. Если же опция выключена, то никакого дополнительного кода в программу не добавляется. Включение опции немного увеличивает размер программы и замедляет её выполнение. Рекомендуется включать эту опцию только в отладочной версии программы.
  • «Overflow checking» — похожа на опцию «Range checking», только проверочный код добавляется для всех арифметических целочисленных операций. Если результат выполнения такой операции выходит за размерность (происходит переполнение результата), то возбуждается исключение класса EIntOverflow. Пример – к байтовой переменной, равной 255, прибавляется 2. Должно получиться 257, но это число больше того, что помещается в байте, поэтому реальный результат будет равен 1. Это и есть переполнение. Эта опция используется редко по трём причинам. Во-первых, самый разный код может рассчитывать на то, что эта опция выключена (часто это различного рода криптографические операции, подсчёт контрольной суммы и т.п., но не только). В связи с этим при включении этой опции могут начаться совершенно различные проблемы. Во-вторых, в обычных ситуациях работают с четырёхбайтовыми знаковыми величинами, и работа около границ диапазонов представления происходит редко. В-третьих, арифметические операции с целыми – достаточно частый код (в отличие от операций с массивами), и добавление дополнительной работы на каждую операцию иногда может быть заметно (в смысле производительности).
  • «I/O Checking» — эта опция используется только при работе с файлами в стиле Паскаля, которые считаются устаревшими. По-хорошему, вы не должны использовать их и, соответственно, эту опцию.

Замечу также, что эти опции можно выставлять и локально — как для целого модуля, так и для отдельной функции/процедуры (а для некоторых опций — даже для участка кода). Делается это обычными директивами компилятора, узнать которые вы можете, нажав F1 в окне настроек. Например, «Stack Frames» регулируется <$W+>и <$W->.

Кроме того, помимо настроек компилятора (Compiling) есть ещё настройки компоновщика (Linking):

  • «Map file» — включение опции заставляет линкёр Delphi создавать вместе с проектом map-файл. Различные установки опции отвечают за уровень детализации и обычно имеет смысл ставить только Off или Detailed. Map файл обычно используется всевозможными утилитами типа EurekaLog, JCL или madExcept в качестве первичного источника для создания отладочной информации в своём формате. Поэтому руками устанавливать эту опцию вам придётся крайне редко — эксперты включают её самостоятельно по необходимости.
  • «Debug Information» (Linker)/«Include TD32 debug info» — внедряет в приложение отладочную информацию для внешнего отладчика в формате TD32. Обычно эта опция включается, если вы отлаживаете проект через Attach to process и Delphi не может найти отладочную информацию. При включении этой опции размер самого приложения увеличивается в 5-10 раз (при условии, что опция «Place debug information in separate TDS file» выключена). Поэтому, если вам нужна отладочная информация в распространяемом приложении — лучше рассмотреть другие варианты (лучше всего подходит отладочная информация в специализированных форматах — EurekaLog, JCL, madExcept).
  • «Include remote debug symbols» — заставляет линкёр создать rsm-файл вместе с проектом, в который записывается информация для удалённого отладчика Delphi. Вам нужно включать эту опцию, если вы хотите выполнить удалённую отладку. Полученный rsm-файлик нужно копировать вместе с приложением на удалённую машину.

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

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

Обычное приложение без механизма диагностики исключений

Общие настройки для любых профилей

Все опции отладки («Debug information» (Compiler), «Local symbols», «Reference info») вообще на готовый модуль не влияют, т.к. отладочная информация в exe/DLL не хранится, ну и нам жить не мешают => поэтому смысла их выключать я не вижу («Use Debug DCUs» — устанавливайте по вкусу, смотря по тому, хотите вы отлаживаться в стандартных модулях или нет).

«Stack Frames» вообще включать незачем.

Генерацию map-файла выключаем.

Профиль Debug

Включаем «Range checking» и (по вкусу) «Overflow checking».

«Include TD32 debug info» — включаем только для отладки внешнего процесса.

Соответственно, «Include remote debug info» — включаем только для удалённой отладки.

Профиль Release

Выключаем «Range checking», «Overflow checking», «Include TD32 debug info» и «Include remote debug info».

Приложение с механизмом диагностики исключений (типа EurekaLog, JCL или madExcept)

Общие настройки любых профилей

Все опции отладки («Debug information» (Compiler), «Local symbols», «Reference info») держать включёнными, т.к. в противном случае не будет доступна отладочная информация. Соответственно, ваши информационные механизмы пойдут лесом.

«Stack Frames» — вообще вЫключать незачем.

Генерацию map-файла включаем, если об этом не позаботился эксперт (маловероятно).

Профиль Debug

«Use Debug DCUs» — по вкусу.
Включаем «Range checking» и (по вкусу) «Overflow checking».

«Include TD32 debug info» — включаем только для отладки внешнего процесса.

«Include remote debug info» — включаем только для удалённой отладки.

Профиль Release

Включаем «Use Debug DCUs».

Выключаем «Range checking», «Overflow checking», «Include TD32 debug info» и «Include remote debug info».

Примечание: если вы используете мало операций с индексами в своей программе (так что дополнительные проверки не замедлят её), то будет хорошей идеей всегда держать опцию «Range checking» включённой.

Что может пойти не так, если настройки будут заданы неверно?

Ну, во-первых, это невозможность отладки (например, отсутствие информации для удалённого отладчика или выключенная опция «Debug information» (Compiler)), большой размер приложения (например, случайно забыли выключить «Debug information» (Linker)/«Include TD32 debug info»), медленная работа (например, компиляция с отладочным кодом), отсутствие или неполный стек вызовов в средствах диагностики исключений (например, выключили «Debug information» (Compiler)). В очень редких и запущенных случаях переключение опций может сказаться на работоспособности программы (например, установка Stack frames может снизить максимально возможную глубину рекурсии). Ну и недочёты по мелочи.

Кстати, если вы разрабатываете компоненты, то надо учитывать, что у Delphi есть именно два набора DCU-файлов, которые отличаются настройками компиляции. Вообще говоря, простое переключение опций, ответственных за генерацию отладочной информации, никак не влияет на интерфейс и реализацию модуля. Но в общем случае код может использовать условные директивы. Поэтому может быть ситуация, когда два набора DCU файлов (скомпилированных с разными опциями) не совместимы друг с другом — потому что они использовали какую-либо директиву и содержат разный код (а вот и пример).
Поэтому вам тоже надо иметь два набора DCU-файлов: один — скомпилированный с опцией «Use Debug DCUs», другой — без. Причём, не важно включена или выключена опция «Debug information» (Compiler) в ваших настройках в обоих случаях.

Примечания:
(*) Слова «отладочная информация увеличивает время компиляции, размер dcu-файлов, но не влияет на размер и скорость работы полученного exe-файла» некоторые понимают неправильно. В частности, многие замечают, что если переключить профиль приложения с Debug на Release (или наоборот), то размер приложения изменится (незначительно или же намного — зависит от настроек проекта и его исходного кода). Позвольте, но ведь я говорю об отладочной информации в чистом виде (мы говорим про опции «Debug Information», «Local Symbols» и т.п. с вкладки «Compiling»), а вы меняете профиль компиляции целиком. Это не только смена опций отладочной информации (которые, кстати, могут даже вообще не меняться при смене профиля), а также и множество других настроек.

Например, в вашем коде может быть тьма конструкций вида <$IFDEF DEBUG>какой-то код <$ENDIF>. Разумеется, когда вы собираете программу в Release, этот код в программу не попадёт, а когда вы собираете его в Debug, то — попадёт. Потому что по умолчанию профиль Debug содержит символ условной компиляции «DEBUG». В результате размер .exe действительно получится разный. Но повлияла ли на этот размер отладочная информация? Неа. Фактически, вы собрали в разных профилях разных код — неудивительно, что он разный по размеру.

Более того, вы можете удалить из конфигурации Debug символ условной компиляции «DEBUG» — и тогда вы будете собирать один и тот же код в обоих профилях. Ну, по крайней мере, свой код. Сторонний, уже собранный код, конечно же, никак не будет затронут. Например, код RTL/VCL уже скомпилирован с фиксированными настройками и не меняется при пересборке проекта. Вон там чуть выше я упомянул, что в некоторых версиях Delphi отладочный и релизный варианты кода RTL/VCL незначительно отличаются — опять же, благодаря условной компиляции. Но никак не отладочной информации.

Кроме того, к иному коду приводит и включение/выключение опций вида Optimization, Stack Frames, Range Check Errors и др. Действительно, оптимизация может удалять код (оптимизировать ненужный) или увеличивать (вставлять inline вместо вызова), Stack Frames очевидно добавляет код (код установки фрейма), равно как и Range Check Errors (код проверки диапазонов). В результате, вы меняете профиль — вы меняете и код (при условии, что разные профили имеют разные настройки вышеупомянутых опций — что так и есть по умолчанию). Меняете код — меняете и размер. Имеет ли хоть какое-то отношение к этому изменению размера отладочная информация? Нет.

Далее, другой пример. Несмотря на то, что по умолчанию отладочная информация в .exe файл не попадает — никто же не запрещает её вам туда добавить самому! Например, если вы будете использовать трейсер исключений, то он самостоятельно добавит в .exe часть отладочной информации, которая нужна ему для построения читабельных стеков вызовов.

Также о внедрении отладочной информации можно попросить и среду. Например, вы можете включить «Include TD32 Debug Info» (эта опция называется «Debug Information» на вкладке «Linking» в последних версиях Delphi) и выключить опцию «Place debug information in separate TDS file». Тогда вся отладочная информация из .dcu файлов будет собрана в один большой файл и этот файл будет внедрён в .exe. Тогда да, отладочная информация повлияет на размер файла, но это происходит не из-за её свойств, а потому что мы явно попросили такое поведение: «добавьте отладочную инфу в мою программу».

Кстати говоря, в последних версиях Delphi здорово поменяли настройки профилей компиляции. Если раньше Release и Debug мало чем отличались, то теперь отличия существенны. Профиль Debug выключает Optimization, но включает Stack Frames (а профиль Release — делает наоборот). Профиль Debug включает отладочную информацию, а Release — отключает. Но оба профиля включают Assert-ы. Также оба профиля включают I/O checks, но выключают overflow и range. В настройках компоновщика (linking) профиль Debug включает TD32 («Debug information») и Remote debug symbols (не для всех платформ). Release, соответственно, выключает эти же опции. И оба профиля не включают Map file и отдельный файл для TD32.

(**) Например: Button1Click состоит всего из двух инструкций: «call A; ret;». Она очень короткая и не использует аргументы или локальные переменные. Поэтому, очевидно, что ей не нужен стековый фрейм. Когда опция «Stack frames» выключена, то для Button1Click стековый фрейм не создаётся (но он создаётся, если опция «Stack frames» будет включена).

Но, для более сложных процедур стековые фреймы будут генерироваться вне зависимости от установки опции «Stack frames».

Например, тоже очень короткая процедура B всегда имеет фрейм. Причина: использование типа String в ShowMessage. Компилятору нужно вставить неявную строковую переменную и неявный try/finally для её освобождения, поэтому процедуре нужен фрейм.

В реальных приложениях фреймы генерируются для 99% процедур. Подробнее: Фреймы на стеке.

$DefinitionInfo — Директива компилятора Delphi

Как сделать свои собственные сообщения при компилляции

Как узнать версию компиллятора ?

Какие есть директивы компилятора?

<$I+>и <$I->— директивы контроля ввода/вывода
<$M>и <$S>— директивы, определяющие размер стека

<$M+>и <$M->— директивы информации времени выполнения о типах
<$Q+>и <$Q->— директивы проверки переполнения целочисленных операций

<$R>— директива связывания ресурсов

<$R+>и <$R->— директивы проверки диапазона

<$APPTYPE CONSOLE>— директива создания консольного приложения

1) Директивы компилятора, разрешающие или запрещающие проверку утверждений.

По умолчанию <$C+>или <$ASSERTIONS ON>
Область действия локальная

Директивы компилятора $C разрешают или запрещают проверку утверждений. Они влияют на работу процедуры Assert,используемой при отладке программ. По умолчанию действует
директива <$C+>и процедура Assert генерирует исключение EAssertionFailed , если проверяемое утверждение ложно.
Так как эти проверки используются только в процессе отладки программы, то перед ее окончательной компиляцией следует указать директиву <$C->. При этом работа процедур Assert будет блокировано и генерация исключений EassertionFailed производиться не будет.
Директивы действуют на весь файл исходного кода независимо от того, в каком месте файла они расположены.

2) Директивы компилятора, включающие и выключающие контроль файлового ввода-вывода.

По умолчанию <$I+>или <$IOCHECKS ON>
Область действия локальная

Директивы компилятора $I включают или выключают автоматический контроль результата вызова процедур ввода-вывода Object Pascal . Если действует директива <$I+>, то при возвращении процедурой ввода-вывода ненулевого значения генерируется исключение EInOutError и в его свойство errorcode заносится код ошибки. Таким образом, при действующей директиве <$I+>операции ввода-вывода располагаются в блоке try . except , имеющем обработчик исключения EInOutError . Если такого блока нет, то обработка производится методом TApplication.HandleException .
Если действует директива <$I->, то исключение не генерируется. В этом случае проверить, была ли ошибка, или ее не было, можно, обратившись к функции IOResult . Эта функция очищает ошибку и возвращает ее код, который затем можно анализировать. Типичное применение директивы <$I->и функции IOResult демонстрирует следующий пример:

AssignFile ( F,s );
Rewrite (F);

<$I+>
i:=IOResult ;
if i <> 0 then
case i of
2 : .
3 : .
end ;

В этом примере на время открытия файла отключается проверка ошибок ввода вывода, затем она опять включается, переменной i присваивается значение, возвращаемое функцией IOResult и, если это значение не равно нулю (есть ошибка), то предпринимаются какие-то действия в зависимости от кода ошибки. Подобный стиль программирования был типичен до введения в Object Pascal механизма обработки исключений. Однако сейчас, по-видимому, подобный стиль устарел и применение директив $I потеряло былое значение.

3) Директивы компилятора, определяющие размер стека

По умолчанию <$M 16384,1048576>
Область действия глобальная

Локальные переменные в процедурах и функциях размещаются в стеке приложения. При каждом вызове процедуры или функции ее локальные переменные помещаются в стек. При выходе из процедуры или функции эти локальные процедуры удаляются из стека.
Директивы компилятора $M задают параметры стека приложения: его минимальный и максимальный размеры. Приложение всегда гарантировано имеет размер стека, равный его минимальной величине. Если при запуске приложения Windows обнаруживает, что не может выделить этот минимальный объем памяти, то выдается сообщение об этой ошибке.
Если во время работы выясняется, что минимального размера стека не хватает, то размер увеличивается на 4 K, но не более, чем до установленного директивой максимального размера. Если увеличение размера стека невозможно из-за нехватки памяти или из-за достижения его максимальной величины, генерируется исключение EStackOverflow . Минимальный размер стека по умолчанию равен 16384 (16K). Этот размер может изменяться параметром minstacksize директивы <$M>или параметром number директивы <$MINSTACKSIZE>.
Максимальный размер стека по умолчанию равен 1,048,576 (1M). Этот размер может изменяться параметром maxstacksize директивы <$M>или параметром number директивы <$MAXSTACKSIZE number >. Значение минимального размера стека может задаваться целым числом в диапазоне между1024 и 2147483647. Значение максимального размера стека должно быть не менее минимального размера и не более 2147483647. Директивы задания размера стека могут включаться только в программу и не должны использоваться в библиотеках и модулях.

В Delphi 1 имеется процедура компилятора <$S>, осуществляющая переключение контроля переполнения стека. Теперь этот процесс полностью автоматизирован и директива <$S>оставлена только для обратной совместимости.

4) Директивы компилятора, включающие и выключающие генерацию информации времени выполнения о типах ( runtime type information — RTTI).

По умолчанию <$M->или <$ TYPEINFO OFF>
Область действия локальная

Директивы компилятора $M включают или выключают генерацию информации времени выполнения о типах ( runtime type information — RTTI). Если класс объявляется в состоянии <$M+>или является производным от класса объявленного в этом состоянии, то компилятор генерирует RTTI о его полях, методах и свойствах, объявленных в разделе published . В противном случае раздел published в классе не допускается. Класс TPersistent , являющийся предшественником большинства классов Delphi и все классов компонентов, объявлен в модуле Classes в состоянии <$M+>. Так что для всех классов, производных от него, заботиться о директиве <$M+>не приходится.

5) Директивы компилятора, включающие и выключающие проверку переполнения при целочисленных операциях

По умолчанию <$Q->или <$OVERFLOWCHECKS OFF>
Область действия локальная

Директивы компилятора $Q включают или выключают проверку переполнения при целочисленных операциях. Под переполнением понимается получение результата, который не может сохраняться в регистре компьютера. При включенной директиве <$Q+>проверяется переполнение при целочисленных операциях +, -, *, Abs , Sqr , Succ , Pred , Inc и Dec . После каждой из этих операций размещается код, осуществляющий соответствующую проверку. Если обнаружено переполнение, то генерируется исключение EIntOverflow . Если это исключение не может быть обработано, выполнение программы завершается.
Директивы $Q проверяют только результат арифметических операций. Обычно они используются совместно с директивами <$R>, проверяющими диапазон значений при присваивании.
Директива <$Q+>замедляет выполнение программы и увеличивает ее размер. Поэтому обычно она используется только во время отладки программы. Однако, надо отдавать себе отчет, что отключение этой директивы приведет к появлению ошибочных результатов расчета в случаях, если переполнение действительно произойдет во время выполнении программы. Причем сообщений о подобных ошибках не будет.

6) Директивы компилятора, включающие и выключающие проверку диапазона целочисленных значений и индексов

По умолчанию <$R>или <$RANGECHECKS OFF>
Область действия локальная

Директивы компилятора $R включают или выключают проверку диапазона целочисленных значений и индексов. Если включена директива <$R+>, то все индексы массивов и строк и все присваивания скалярным переменным и переменным с ограниченным диапазоном значений проверяются на соответствие значения допустимому диапазону. Если требования диапазона нарушены или присваиваемое значение слишком велико, генерируется исключение ERangeError . Если оно не может быть перехвачено, выполнение программы завершается.
Проверка диапазона длинных строк типа Long strings не производится.
Директива <$R+>замедляет работу приложения и увеличивает его размер. Поэтому она обычно используется только во время отладки.

6) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Директива компилятора <$R>указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows . По умолчанию расширение файлов ресурсов — .RES.
В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах <$R>, копируются в выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву <$R>, а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories / Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.
При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл . pas директиву <$R *.DFM>, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и генерируется исключение EResNotFound .


Все установленные в настройках опции компиляции можно вставить непосредственно в текст программы нажав клавиши Ctrl-O , O

Как сделать свои собственные сообщения при компилляции ?

destructor TumbSelectionTempTable.Destroy ;
begin
// Clear the temp tables.
<$MESSAGE Warn ' - remember to free all allocated objects'>
ClearAllOuterWorldFold ;
if FSubjectsTempTableCreated then
DropTempTable ( FTableName );

FOuterWorldsFolded.Free ;
FQuery.Free ;
inherited ;
end ;

Работает только в Дельфи 6/7

Как узнать версию компилятора?

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

В Дельфи предопределены специальные константы компиляции для этого:

Ver80 — Дельфи 1
Ver90 — Дельфи 2
Ver93 — С Buider 1
Ver100 — Дельфи 3
Ver110 — С Buider 3
Ver120 — Дельфи 4
Ver125 — С Buider 4
Ver130 — Дельфи 5
Ver140 — Дельфи 6
Ver150 — Дельфи 7

procedure TForm1.Button2Click( Sender : TObject );
const Version=

$DefinitionInfo — Директива компилятора Delphi

<$M>и — директивы, определяющие размер стека

<$M+>и — директивы информации времени выполнения о типах

<$Q+>и — директивы проверки переполнения целочисленных операций

— директива связывания ресурсов

<$R+>и — директивы проверки диапазона

<$APPTYPE CONSOLE> — директива создания консольного приложения

1) Директивы компилятора, разрешающие или запрещающие проверку утверждений.

По умолчанию или

Область действия локальная

Директивы компилятора $C разрешают или запрещают проверку утверждений. Они влияют на работу процедуры Assert,используемой при отладке программ. По умолчанию действует директива и процедура Assert генерирует исключение EAssertionFailed, если проверяемое утверждение ложно.

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

Директивы действуют на весь файл исходного кода независимо от того, в каком месте файла они расположены.

2) Директивы компилятора, включающие и выключающие контроль файлового ввода-вывода.

По умолчанию или

Область действия локальная

Директивы компилятора $I включают или выключают автоматический контроль результата вызова процедур ввода-вывода Object Pascal. Если действует директива , то при возвращении процедурой ввода-вывода ненулевого значения генерируется исключение EInOutError и в его свойство errorcode заносится код ошибки. Таким образом, при действующей директиве <$I+>операции ввода-вывода располагаются в блоке try. except, имеющем обработчик исключения EInOutError. Если такого блока нет, то обработка производится методом TApplication.HandleException.

Если действует директива , то исключение не генерируется. В этом случае проверить, была ли ошибка, или ее не было, можно, обратившись к функции IOResult. Эта функция очищает ошибку и возвращает ее код, который затем можно анализировать. Типичное применение директивы и функции IOResult демонстрирует следующий пример:

<$I+>
i:=IOResult;
if i<>0 then
case i of
2: .
3: .
.
end;

В этом примере на время открытия файла отключается проверка ошибок ввода вывода, затем она опять включается, переменной i присваивается значение, возвращаемое функцией IOResult и, если это значение не равно нулю (есть ошибка), то предпринимаются какие-то действия в зависимости от кода ошибки. Подобный стиль программирования был типичен до введения в Object Pascal механизма обработки исключений. Однако сейчас, по-видимому, подобный стиль устарел и применение директив $I потеряло былое значение.

3) Директивы компилятора, определяющие размер стека

По умолчанию <$M 16384,1048576>

Область действия глобальная

Локальные переменные в процедурах и функциях размещаются в стеке приложения. При каждом вызове процедуры или функции ее локальные переменные помещаются в стек. При выходе из процедуры или функции эти локальные процедуры удаляются из стека.

Директивы компилятора $M задают параметры стека приложения: его минимальный и максимальный размеры. Приложение всегда гарантировано имеет размер стека, равный его минимальной величине. Если при запуске приложения Windows обнаруживает, что не может выделить этот минимальный объем памяти, то выдается сообщение об этой ошибке.

Если во время работы выясняется, что минимального размера стека не хватает, то размер увеличивается на 4 K, но не более, чем до установленного директивой максимального размера. Если увеличение размера стека невозможно из-за нехватки памяти или из-за достижения его максимальной величины, генерируется исключение EStackOverflow. Минимальный размер стека по умолчанию равен 16384 (16K). Этот размер может изменяться параметром minstacksize директивы <$M>или параметром number директивы .

Максимальный размер стека по умолчанию равен 1,048,576 (1M). Этот размер может изменяться параметром maxstacksize директивы или параметром number директивы . Значение минимального размера стека может задаваться целым числом в диапазоне между1024 и 2147483647. Значение максимального размера стека должно быть не менее минимального размера и не более 2147483647. Директивы задания размера стека могут включаться только в программу и не должны использоваться в библиотеках и модулях.

В Delphi 1 имеется процедура компилятора , осуществляющая переключение контроля переполнения стека. Теперь этот процесс полностью автоматизирован и директива оставлена только для обратной совместимости.

4) Директивы компилятора, включающие и выключающие генерацию информации времени выполнения о типах (runtime type information — RTTI).

По умолчанию или

Область действия локальная

Директивы компилятора $M включают или выключают генерацию информации времени выполнения о типах (runtime type information — RTTI). Если класс объявляется в состоянии <$M+>или является производным от класса объявленного в этом состоянии, то компилятор генерирует RTTI о его полях, методах и свойствах, объявленных в разделе published. В противном случае раздел published в классе не допускается. Класс TPersistent, являющийся предшественником большинства классов Delphi и все классов компонентов, объявлен в модуле Classes в состоянии . Так что для всех классов, производных от него, заботиться о директиве не приходится.

5) Директивы компилятора, включающие и выключающие проверку переполнения при целочисленных операциях

По умолчанию или

Область действия локальная

Директивы компилятора $Q включают или выключают проверку переполнения при целочисленных операциях. Под переполнением понимается получение результата, который не может сохраняться в регистре компьютера. При включенной директиве проверяется переполнение при целочисленных операциях +, -, *, Abs, Sqr, Succ, Pred, Inc и Dec. После каждой из этих операций размещается код, осуществляющий соответствующую проверку. Если обнаружено переполнение, то генерируется исключение EIntOverflow. Если это исключение не может быть обработано, выполнение программы завершается.

Директивы $Q проверяют только результат арифметических операций. Обычно они используются совместно с директивами , проверяющими диапазон значений при присваивании.

Директива замедляет выполнение программы и увеличивает ее размер. Поэтому обычно она используется только во время отладки программы. Однако, надо отдавать себе отчет, что отключение этой директивы приведет к появлению ошибочных результатов расчета в случаях, если переполнение действительно произойдет во время выполнении программы. Причем сообщений о подобных ошибках не будет.

6) Директивы компилятора, включающие и выключающие проверку диапазона целочисленных значений и индексов

По умолчанию или

Область действия локальная

Директивы компилятора $R включают или выключают проверку диапазона целочисленных значений и индексов. Если включена директива , то все индексы массивов и строк и все присваивания скалярным переменным и переменным с ограниченным диапазоном значений проверяются на соответствие значения допустимому диапазону. Если требования диапазона нарушены или присваиваемое значение слишком велико, генерируется исключение ERangeError. Если оно не может быть перехвачено, выполнение программы завершается.

Проверка диапазона длинных строк типа Long strings не производится.

Директива замедляет работу приложения и увеличивает его размер. Поэтому она обычно используется только во время отладки.

7) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Директива компилятора указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows. По умолчанию расширение файлов ресурсов — .RES.

В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах , копируются в выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву , а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories/Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.

При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл .pas директиву <$R *.DFM>, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и генерируется исключение EResNotFound.

r3code

VALID INFO! My crazy life!

Задержись в реальности!

Столкнулся с проблемой сборки приложения из скрипта командной строки dcc32 неправильно обрабатывает параметры -B -D.
Приложение — тестовый проект DUnit, который должен запускаться, как консольное приложение.

Вот оновной код проекта:

dcc32 -B projTests.dpr должно заново компилировать все юниты, но это не происходит.
dcc32 -B -DCONSOLE_TESTRUNNER projTests.dpr не обрабатывает директиву компиляции или не перекомпилируюе юниты, потому я получаю опять GUI приложение вместо консольного.

Причем даже из самой среды команда Build All не помогает, то же самое. Однакое если сделать Build All и Compile, то проект собирается правильно.
Это и стало решением.

Сначала собираю проект

Затем еще раз компилирую

В этом случае на выходе получаю консльное приложение, как надо.

Илон Маск рекомендует:  Что такое код setaspectratio
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL