Как определить версию "и вверх" ifdefs в Delphi?
Я работал над тем, чтобы Log4D работал в Delphi XE4 и получал некоторые ошибки компиляции, потому что он не мог найти Contnrs в предложении uses, если только я не переместил его за пределы ifdef, в котором он был определен.
{$IFDEF DELPHI5_UP}
Contnrs,
{$ENDIF}
Немного разобравшись, выяснилось, что ifdef определен во включенном файле Defines.inc, который имеет блок для каждой поддерживаемой версии delphi, которая останавливает несколько версий:
например:
{$IFDEF VER170} { Delphi 2005 }
{$DEFINE DELPHI9}
{$DEFINE DELPHI4_UP}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
{$ENDIF}
{$IFDEF VER180} { Delphi 2006 }
{$DEFINE DELPHI10}
{$DEFINE DELPHI4_UP}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$DEFINE DELPHI7_UP}
Итак, хотя было бы довольно легко пойти и скопировать и вставить ifdef для Delphi 2006 и создать блок Delphi XE4... это похоже на неэлегантное решение. Это определенно не будущее доказательство... каждая новая версия вам нужно обновить этот файл сейчас, поэтому некоторый код, отсутствующий в Delphi 4, не заставит кого-то еще 15 летнего старого кода взорваться.
Итак, мне было интересно, есть ли лучший способ сделать условную компиляцию, чтобы она действительно проверяла, есть ли у вас "Delphi 5 или выше" при компиляции этой строки, а не в этом формате, который требует обновления каждой новой версии delphi это выходит.
Ответы
Ответ 1
IIRC, Delphi 6 ввели условные выражения, которые на самом деле были предложены TLama. Чтобы ваш код работал с версиями Delphi ниже этого, вы должны проверить {$IFDEF CONDITIONALEXPRESSIONS }
. Если это не определено, вам нужно использовать старую схему VERxxx
, чтобы различать версии Delphi.
Для Delphi 6 и выше вы можете использовать встроенные константы CompilerVersion
и RTLVersion
. Какой из них вы используете, зависит от вашего кода. Всякий раз, когда вы используете новый тест функции компилятора для CompilerVersion
. Для всего, что связано с тестом RTL или VCL для RTLVersion
.
Всегда полезно прокомментировать предыдущий компилятор и использовать условную часть для совместимости с более старыми версиями. Поэтому вместо написания {$IF CompilerVersion >= 26.0}
напишите свой код так, чтобы использовался {$IF CompilerVersion < 26.0}
. Таким образом, в будущем гораздо проще отказаться от поддержки старых версий компилятора.
Ответ 2
Если бы я был поставщиком компонентов (TMS, DevEx), я мог бы чувствовать себя вынужденным придерживаться длинного подробного синтаксиса, который когда-либо поддерживал КАЖДЫЙ delphi. Вот почему этот большой беспорядок существует в большинстве кодовых баз компонентов.
Тем не менее, для моих собственных компонентов я не обновляю каждую версию, которая появляется, потому что мой файл ver.inc выглядит так, и я не поддерживаю версии Delphi вообще, которые не поддерживают этот новый синтаксис:
{ver.inc}
{ MYSOFT VERSION DEFINES }
{$IF CompilerVersion >= 22.0}
{$DEFINE RTL220_UP}
{$DEFINE XE_UP}
{$IFEND}
{$IF CompilerVersion >= 23.0}
{$DEFINE RTL230_UP}
{$DEFINE XE2_UP}
{$IFEND}
{$IF CompilerVersion >= 24.0}
{$DEFINE RTL240_UP}
{$DEFINE XE3_UP}
{$IFEND}
{$IF CompilerVersion >= 25.0}
{$DEFINE RTL250_UP}
{$DEFINE XE4_UP}
{$IFEND}
{$IF CompilerVersion >= 26.0}
{$DEFINE RTL250_UP}
{$DEFINE XE5_UP}
{$IFEND}
{$DEFINE OTHER_THING}
Ничего в коде выше не разрывается, когда выходит новая версия delphi. Обратите внимание, что мне НЕ нужно поддерживать Delphi 5 по 2010 с моими кодами. Фактически, я поддерживаю только XE2 и выше.
Несколько более длинная версия вышеуказанной формы может использоваться для поддержки каждой версии Delphi 6 и выше без каких-либо повторяющихся блоков и без прерывания при каждом выпуске новой версии delphi.
Также см. ответ Uwe для метода, в котором вы можете создать один .inc файл, который поддерживает КАЖДУЮ версию, и использовать только старую форму для старых версий delphi.
Ответ 3
В интересах любого, кто придет найти этот вопрос в будущем, я подумал, что, возможно, стоит задокументировать мое окончательное решение, поскольку оно потребовало объединения небольших бит от всех ответов и комментариев, чтобы заставить его работать, и он нашел меня еще несколько примеров, чтобы действительно понять, как использовать некоторые из приведенных выше предложений.
Чтобы обрабатывать версии до Delphi 6, которые не поддерживают {$IF}
, я оставил их как as-is. В лучшем случае у вас будет 5 таких, но в моем случае это было всего 2:
{$IFDEF VER120} { Delphi 4 }
{$DEFINE DELPHI4}
{$DEFINE DELPHI4_UP}
{$ENDIF}
{$IFDEF VER130} { Delphi 5 }
{$DEFINE DELPHI4_UP}
{$DEFINE DELPHI5_UP}
{$ENDIF}
И затем для версий, поддерживающих {$ IF} (Delphi 6+), я завернул их в блок {$IFDEF CONDITIONALEXPRESSIONS }
, как это было предложено Uwe. Документация Embarcadero показала хороший пример этого, как только я узнал правильные условия поиска.
Это, в сочетании с предложением Уоррена об использовании блоков IF на большей или равной версии компилятора значительно упростило ситуацию:
{$IFDEF CONDITIONALEXPRESSIONS} { Delphi 6+ }
{$IF CompilerVersion >= 14.0} { Delphi 6+ }
{$DEFINE DELPHI4_UP}
{$DEFINE DELPHI5_UP}
{$DEFINE DELPHI6_UP}
{$IFEND}
{$IF CompilerVersion >= 15.0} { Delphi 7+ }
{$DEFINE DELPHI7_UP}
{$IFEND}
{$ENDIF}
Embarcadero имеет полезную целую диаграмму со всеми версиями Delphi и их именованными константами и обычным именем пакета. Между тем и этим ответом на переполнение стека я смог заполнить все константы версии компилятора.
Как только я получил этот блок там, мне даже не нужны блоки Delphi 2005/2006 в моем вопросе вообще, и XE4 счастливо компилируется.
Мне понравилось предлагать кодирование для версии X и ниже, а не Y и выше, когда это возможно, хотя я и не смог сразу использовать это предложение, так как это было бы столько, чтобы переработать IFs и IFDEF, это было бы прежде всего, чтобы вырвать поддержку для Delphi 3; -).
Ответ 4
Ответ проще, чем я думал. Из документации:
Например, чтобы определить версию компилятора и библиотеки времени выполнения, которые использовались для компиляции вашего кода, вы можете использовать {$ IF} с CompilerVersion, RTLVersion и другими константами.
{$IFDEF CONDITIONALEXPRESSIONS}
{$IF CompilerVersion >= 23.0}
...
{$IFEND}
{$ENDIF}
где версия 23.0
означает в данном случае Delphi XE2.
Полный список версий Delphi вы можете найти здесь.