Skip to content

Fr0sT-Brutal/Delphi_Compilers

Repository files navigation

Include files for checking compiler versions and capabilities

With these files you can write code that is compatible with older Delphi compilers or even other Pascal compilers (FreePascal) by simply enclosing modern/specific constructions with appropriate define. Moreover you don't have to check compiler version where a required feature first appeared, you just check the availability of this feature.

Additionally, there are files for checking current compiler settings in CompilerOpts.inc, some cross-compiler and cross-platform defines in XPlatformCompat.inc and cross-compiler declarations in XCompiler.*.pas

Summary

  • Supports Delphi 7 (see note below), RAD Studio 2005+, FreePascal
  • Contains only a few of RTL/VCL changes (feel free to suggest)
  • Compatible with JVCL defines (only some of them are included)
  • Several ways of implementing conditional defines

Delphi 7 support

In fact, the files only add one define DCC for Delphi 7. We consider language and compiler features implemented in Delphi 7 as a base and track all changes from it. Older versions are not supported because they have no $IF clause.

General hints

  • Where possible, use capabilities instead of versions checking for greater clearness and portability.

    DON'T:

    function Foo; {$IF CompilerVersion >= RAD_2005}inline;{$IFEND}

    DO:

    function Foo; {$IFDEF CAPS_INLINE}inline;{$IFEND}
  • Check existense of types/constants/vars by {$IF DECLARED()}.

    DON'T:

    var s: {$IFDEF UNICODE}UnicodeString{$ELSE}WideString{$IFEND};

    DO:

    var s: {$IF DECLARED(UnicodeString)}UnicodeString{$ELSE}WideString{$IFEND};

    ❗ Be careful with declaration and implementation sections! If you declare something in declaration section, $IF DECLARED will always be true. Use additional define for this case.

    {$IF NOT DECLARED(IsNumber)}
      {$DEFINE NO_IsNumber}
      function IsNumber(C: Char): Boolean;
    {$IFEND};
    
    ...
    
    {$IFDEF NO_IsNumber}
    function IsNumber(C: Char): Boolean;
    begin
      ...
    end;
    {$ENDIF}
  • Minimize usage of $IF checks as much as possible.

    DON'T:

    var i: {$IFDEF CPU64}Int64{$ENDIF} {$IFDEF CPU32}Int32{$ENDIF};
    function Foo: {$IFDEF CPU64}Int64{$ENDIF} {$IFDEF CPU32}Int32{$ENDIF};

    DO (imagine we don't have NativeInt):

    type CPUInt = {$IFDEF CPU64}Int64{$ENDIF} {$IFDEF CPU32}Int32{$ENDIF};
    var i: CPUInt;
    function Foo: CPUInt;

    ℹ️ CPU32/CPU64 are FPC-style defines determining just the bitness of a CPU. Delphi analogs are CPU32BITS/CPU64BITS. CPU32/CPU64 for Delphi are defined in XPlatformCompat.inc file.

    ❗ A bad practice is very frequent in CPU bitness check ({$IFDEF CPU64} ...x64... {$ELSE} ...x32? We hope so... {$ENDIF}). Usually code asserts no other bitness exists besides 64 and 32. This is NOT true (FPC is able to build for 16-bit CPUs and probably someday there will appear 128-bit CPUs). So we use straight conditions for known bitnesses; unsupported ones will generate compiler error.

Editions

There are two editions of the include file.

  1. Define-only edition in CompilersDef.inc. Contains only compiler defines, thus supports including into any part of a unit, even before the first line of a unit. Under RAD Studio contains compiler version defines named like RAD_%VER%_UP where %VER% is RAD Studio version (2005-2010, XE, XE2-7...). These defines are identical to frequently used COMPILER_##_UP ones.

  2. Declaration edition in CompilersDecl.inc. Contains some constant declarations, thus allowing more convenient usage. Could be included ONLY in declaration section and below so defines based on this include couldn't be utilized in "uses" section.

You may use the one you need or even both altogether. Internally CompilersDecl.inc includes CompilersDef.inc.

Usage

  1. Check for compiler version (avoid where possible)

Declaration edition

{$IF CompilerVersion >= RAD_2005}
  ...
{$IFEND}

Define-only edition

{$IFDEF RAD_2005_UP}
  ...
{$IFEND}

ℹ️ Note. Version constants are actual for Delphi/RAD only. It is supposed that FPC users use fresh version so there's no need in checking the capabilities of its older versions.

  1. Check for compiler capability

    1. Traditional
    {$IFDEF CAPS_REGION}
      {$REGION 'Foo'}
    {$ENDIF}

    Drawback is that you have to remember all names of defines.

    1. Modern style (only with Declaration edition)
    {$IF Cap_Region}
      ...
    {$IFEND}

    Here you can get Code Insight's help to find out the needed capability as it is actually a usual boolean constant.

    ❗ Note that constants are named Cap_* while defines are named CAPS_ to avoid ambiguity with FPC as it allows $IF %Define_name% construction.

    Sometimes this option is impossible though and you have to use traditional check

    uses {$IFDEF HAS_UNITSCOPE}Winapi.Windows{$ELSE}Windows{$IFEND}, ...

Defined capabilities

Please refer to CompilersDef.inc for the list of currently defined capabilities. When using "Modern style" defines you'll get the list of available capabilities with Code Insight.

If you find something to add, feel free to suggest it (please check CONTRIBUTING.md first). But note only those defines will be added that couldn't be determined via $IF clauses.

WARNING

Some features of RAD Studio ignore all define areas that use $IF construction explicitly or implicitly (still not fixed!). This means no autogenerating of methods, Jump to decl/impl etc. Really annoying and stupid bug. Code Insight still works though.

About

Include files for checking compiler versions and capabilities

Topics

Resources

License

Stars

Watchers

Forks