How to define version "and up" ifdefs in Delphi?
IIRC, Delphi 6 introduced conditional expressions, which are actually what TLama suggested. To make your code work with Delphi versions below that, you have to check for {$IFDEF CONDITIONALEXPRESSIONS }
. If this is not defined, you have to use the old VERxxx
scheme to distinguish between the Delphi versions.
For Delphi 6 and higher you can use the built-in constants CompilerVersion
and RTLVersion
. Which of these you use depends on your code. Whenever you use a new compiler feature test for CompilerVersion
. For anything related to the RTL or VCL test for RTLVersion
.
It is always a good idea to code against the newest compiler and only use the conditional part for compatibility to older versions. So instead of writing {$IF CompilerVersion >= 26.0}
write your code in a way that {$IF CompilerVersion < 26.0}
is used. Thus in the future it is much easier to drop support for older compiler versions.
If I was a component vendor (TMS, DevEx) I might feel compelled to stick with the long, verbose syntax that EVERY delphi version ever supports. That's why that big mess is there in most component codebases.
Yet, for my own in-house components, I do not update with every version that comes out because my ver.inc file looks like this, and I do not support Delphi versions at all that do not support this newer syntax:
{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}
Nothing in the code above breaks when a new delphi version comes out. Note that I DO NOT have to support Delphi 5 through 2010 with my codebases. In fact, I only support XE2 and up.
A slightly longer version of the above form could be used to support every version from Delphi 6 and up, without any repeated blocks, and without breaking each time a new delphi version releases.
Also, see Uwe's answer for a technique where you can build one .inc file that supports EVERY version, and only use the old form for the old delphi versions.
For the benefit of anyone coming to find this question in the future, I thought it might be worth documenting my final solution, since it took combining little bits from all the answers and comments to make it work, and it took finding me a few more examples to really understand how to use some of the suggestions above.
To handle the versions prior to Delphi 6 that don't support {$IF}
, I left them as as-is. At most you'd have 5 of those, but in my case it was only 2:
{$IFDEF VER120} { Delphi 4 }
{$DEFINE DELPHI4}
{$DEFINE DELPHI4_UP}
{$ENDIF}
{$IFDEF VER130} { Delphi 5 }
{$DEFINE DELPHI4_UP}
{$DEFINE DELPHI5_UP}
{$ENDIF}
And then for the versions that support {$IF} (Delphi 6+) I wrapped them in an {$IFDEF CONDITIONALEXPRESSIONS }
block as suggested by Uwe. The Embarcadero documentation turned out to give a nice example of this, once I knew the right search terms.
That, combined with Warren's suggestion of using IF blocks on greater than or equal to the compiler version simplified things significantly:
{$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 has a helpful whole chart with all the versions of Delphi and their named constants, and customary Package Name. Between that and this stack overflow answer I was able to fill in all the compiler version constants.
Once I got this block in there, I didn't even need the the Delphi 2005/2006 blocks in my question at all and XE4 happily compiles away.
I liked Uwe's suggestion of coding for version X and below rather than Y and above when possible, even though I didn't end up using that suggestion immediately, since it would have been as much to rework the IFs and IFDEFs it would be to rip out the support for Delphi 3 in the first place ;-).
The answer is simpler than I thought. From the documentation:
For example, to determine the version of the compiler and run-time library that were used to compile your code, you can use {$IF} with the CompilerVersion, RTLVersion and other constants.
Here is the full code detecting Delphi versions from 6 to 10.3 (Rio):
{$IFNDEF FPC}
{$IF CompilerVersion >= 33.0}
{$DEFINE DELPHI_10_3_RIO_UP}
{$IFEND}
{$IF CompilerVersion >= 32.0}
{$DEFINE DELPHI_10_2_TOKYO_UP}
{$IFEND}
{$IF CompilerVersion >= 31.0}
{$DEFINE DELPHI_10_1_BERLIN_UP}
{$IFEND}
{$IF CompilerVersion >= 30.0}
{$DEFINE DELPHI_10_SEATTLE_UP}
{$IFEND}
{$IF CompilerVersion >= 29.0}
{$DEFINE DELPHI_XE8_UP}
{$IFEND}
{$IF CompilerVersion >= 28.0}
{$DEFINE DELPHI_XE7_UP}
{$IFEND}
{$IF CompilerVersion >= 27.0}
{$DEFINE DELPHI_XE6_UP}
{$IFEND}
{$IF CompilerVersion >= 26.0}
{$DEFINE DELPHI_XE5_UP}
{$IFEND}
{$IF CompilerVersion >= 25.0}
{$DEFINE DELPHI_XE4_UP}
{$IFEND}
{$IF CompilerVersion >= 24.0}
{$DEFINE DELPHI_XE3_UP}
{$IFEND}
{$IF CompilerVersion >= 23.0}
{$DEFINE DELPHI_XE2_UP}
{$IFEND}
{$IF CompilerVersion >= 22.0}
{$DEFINE DELPHI_XE_UP}
{$IFEND}
{$IF CompilerVersion >= 21.0}
{$DEFINE DELPHI_2010_UP}
{$IFEND}
{$IF CompilerVersion >= 20.0}
{$DEFINE DELPHI_2009_UP}
{$IFEND}
{$IF CompilerVersion >= 19.0}
{$DEFINE DELPHI_2007_FOR_NET_UP}
{$IFEND}
{$IF CompilerVersion >= 18.5}
{$DEFINE DELPHI_2007_UP}
{$IFEND}
{$IF CompilerVersion >= 18.0}
{$DEFINE DELPHI_2006_UP}
{$IFEND}
{$IF CompilerVersion >= 17.0}
{$DEFINE DELPHI_2005_UP}
{$IFEND}
{$IF CompilerVersion >= 16.0}
{$DEFINE DELPHI_8_FOR_NET_UP}
{$IFEND}
{$IF CompilerVersion >= 15.0}
{$DEFINE DELPHI_7_UP}
{$IFEND}
{$IF CompilerVersion >= 14.0}
{$DEFINE DELPHI_6_UP}
{$IFEND}
{$ENDIF}
The whole compiler version list you can find for example here.