program KolDefGen;
{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}
(*-----------------------------------------------------------------------------
KolDefGen - regenerates koldef.inc, extended with one new Delphi version.
Usage:
koldefgen <vernum> [shortname] [comment] [outputfile]
Examples:
koldefgen 370
koldefgen 370 _D13 "Delphi 13"
koldefgen 370 _D13 "Delphi 13" koldef.inc
<vernum> the number after VER in the new {$IFDEF VERxxx}, e.g. for
{$IFDEF VER370} pass 370. This is the only required argument.
[shortname] identifier used for the version, e.g. _D13. Defaults to
'_DVER<vernum>' if omitted.
[comment] free text put in the generated comment, e.g. "Delphi 13".
Defaults to 'Delphi (VER<vernum>)' if omitted.
[outputfile] defaults to koldef.inc in the current directory.
Only Delphi version handling is generated here; the FPC-specific block
is emitted unchanged/static, as agreed - extend separately if needed.
-----------------------------------------------------------------------------*)
uses
SysUtils, Classes;
type
TVerEntry = record
VerNum: Integer;
OwnDefines: TArray<string>; // defines set only for this exact version
HigherDefines: TArray<string>; // cascading defines from this version up
Comment: string;
end;
var
KnownVersions: TArray<TVerEntry>;
procedure InitKnownVersions;
begin
SetLength(KnownVersions, 22);
KnownVersions[0].VerNum := 140; KnownVersions[0].OwnDefines := ['_D6'];
KnownVersions[0].HigherDefines := ['_D6orHigher']; KnownVersions[0].Comment := 'Delphi 6';
KnownVersions[1].VerNum := 150; KnownVersions[1].OwnDefines := ['_D7'];
KnownVersions[1].HigherDefines := ['_D7orHigher']; KnownVersions[1].Comment := 'Delphi 7';
KnownVersions[2].VerNum := 170; KnownVersions[2].OwnDefines := ['_D8', '_D2005'];
KnownVersions[2].HigherDefines := ['_D8orHigher', '_D2005orHigher'];
KnownVersions[2].Comment := 'Delphi 2005 (also known as D8 .NET)';
KnownVersions[3].VerNum := 180; KnownVersions[3].OwnDefines := ['_D2006'];
KnownVersions[3].HigherDefines := ['_D2006orHigher']; KnownVersions[3].Comment := 'Delphi 2006';
KnownVersions[4].VerNum := 185; KnownVersions[4].OwnDefines := ['_D2007'];
KnownVersions[4].HigherDefines := ['_D2007orHigher']; KnownVersions[4].Comment := 'Delphi 2007';
KnownVersions[5].VerNum := 200; KnownVersions[5].OwnDefines := ['_D2009'];
KnownVersions[5].HigherDefines := ['_D2009orHigher']; KnownVersions[5].Comment := 'Delphi 2009';
KnownVersions[6].VerNum := 210; KnownVersions[6].OwnDefines := ['_D2010'];
KnownVersions[6].HigherDefines := ['_D2010orHigher']; KnownVersions[6].Comment := 'Delphi 2010';
KnownVersions[7].VerNum := 220; KnownVersions[7].OwnDefines := ['_DXE'];
KnownVersions[7].HigherDefines := ['_DXEorHigher']; KnownVersions[7].Comment := 'Delphi XE';
KnownVersions[8].VerNum := 230; KnownVersions[8].OwnDefines := ['_DXE2'];
KnownVersions[8].HigherDefines := ['_DXE2orHigher']; KnownVersions[8].Comment := 'Delphi XE2';
KnownVersions[9].VerNum := 240; KnownVersions[9].OwnDefines := ['_DXE3'];
KnownVersions[9].HigherDefines := ['_DXE3orHigher']; KnownVersions[9].Comment := 'Delphi XE3';
KnownVersions[10].VerNum := 250; KnownVersions[10].OwnDefines := ['_DXE4'];
KnownVersions[10].HigherDefines := ['_DXE4orHigher']; KnownVersions[10].Comment := 'Delphi XE4';
KnownVersions[11].VerNum := 260; KnownVersions[11].OwnDefines := ['_DXE5'];
KnownVersions[11].HigherDefines := ['_DXE5orHigher']; KnownVersions[11].Comment := 'Delphi XE5';
KnownVersions[12].VerNum := 270; KnownVersions[12].OwnDefines := ['_DXE6'];
KnownVersions[12].HigherDefines := ['_DXE6orHigher']; KnownVersions[12].Comment := 'Delphi XE6';
KnownVersions[13].VerNum := 280; KnownVersions[13].OwnDefines := ['_DXE7'];
KnownVersions[13].HigherDefines := ['_DXE7orHigher']; KnownVersions[13].Comment := 'Delphi XE7';
KnownVersions[14].VerNum := 290; KnownVersions[14].OwnDefines := ['_DXE8'];
KnownVersions[14].HigherDefines := ['_DXE8orHigher']; KnownVersions[14].Comment := 'Delphi XE8';
KnownVersions[15].VerNum := 300; KnownVersions[15].OwnDefines := ['_D10'];
KnownVersions[15].HigherDefines := ['_D10orHigher']; KnownVersions[15].Comment := 'Delphi 10 Seattle';
KnownVersions[16].VerNum := 310; KnownVersions[16].OwnDefines := ['_D101'];
KnownVersions[16].HigherDefines := ['_D101orHigher']; KnownVersions[16].Comment := 'Delphi 10.1 Berlin';
KnownVersions[17].VerNum := 320; KnownVersions[17].OwnDefines := ['_D102'];
KnownVersions[17].HigherDefines := ['_D102orHigher']; KnownVersions[17].Comment := 'Delphi 10.2 Tokyo';
KnownVersions[18].VerNum := 330; KnownVersions[18].OwnDefines := ['_D103'];
KnownVersions[18].HigherDefines := ['_D103orHigher']; KnownVersions[18].Comment := 'Delphi 10.3 Rio';
KnownVersions[19].VerNum := 340; KnownVersions[19].OwnDefines := ['_D104'];
KnownVersions[19].HigherDefines := ['_D104orHigher']; KnownVersions[19].Comment := 'Delphi 10.4 Sydney';
KnownVersions[20].VerNum := 350; KnownVersions[20].OwnDefines := ['_D11'];
KnownVersions[20].HigherDefines := ['_D11orHigher']; KnownVersions[20].Comment := 'Delphi 11 Alexandria';
KnownVersions[21].VerNum := 360; KnownVersions[21].OwnDefines := ['_D12'];
KnownVersions[21].HigherDefines := ['_D12orHigher']; KnownVersions[21].Comment := 'Delphi 12 Athens';
end;
function IndexOfVerNum(const AVerNum: Integer): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to High(KnownVersions) do
if KnownVersions[i].VerNum = AVerNum then
Exit(i);
end;
procedure AppendVersion(const AVerNum: Integer; const AShortName, AComment: string);
var
n: Integer;
e: TVerEntry;
begin
if IndexOfVerNum(AVerNum) >= 0 then
raise Exception.CreateFmt('VER%d is already a known version - nothing to add.', [AVerNum]);
e.VerNum := AVerNum;
e.OwnDefines := [AShortName];
e.HigherDefines := [AShortName + 'orHigher'];
e.Comment := AComment;
n := Length(KnownVersions);
SetLength(KnownVersions, n + 1);
KnownVersions[n] := e;
// keep the table sorted by VerNum ascending (simple insertion sort step)
while (n > 0) and (KnownVersions[n - 1].VerNum > KnownVersions[n].VerNum) do
begin
e := KnownVersions[n - 1];
KnownVersions[n - 1] := KnownVersions[n];
KnownVersions[n] := e;
Dec(n);
end;
end;
function BuildFile: TStringList;
var
L: TStringList;
i, j: Integer;
cumulativeHigher: TArray<string>;
d: string;
begin
L := TStringList.Create;
L.Add('(*-----------------------------------------------------------------------------');
L.Add(' Version detection for Delphi and Free Pascal');
L.Add(Format(' Supports Delphi 2..%s and FPC 2.6+', [KnownVersions[High(KnownVersions)].Comment]));
L.Add(' NOTE: This version avoids {$IF CompilerVersion >= N} entirely.');
L.Add(' Delphi 6/7 support {$IFDEF CONDITIONALEXPRESSIONS} but their {$IF}');
L.Add(' evaluator does not reliably handle comparisons against CompilerVersion');
L.Add(' (especially real-number comparisons like >= 18.5), so every "orHigher"');
L.Add(' symbol below is set explicitly per {$IFDEF VERxxx} block instead.');
L.Add(' This file was generated by koldefgen - do not hand-edit the version');
L.Add(' cascade below; re-run the generator instead.');
L.Add('-----------------------------------------------------------------------------*)');
L.Add('');
L.Add('{--- Delphi 2 .. 5 (no CONDITIONALEXPRESSIONS) ------------------------------}');
L.Add('{$IFDEF VER90} // Delphi 2');
L.Add(' {$DEFINE _D2}');
L.Add(' {$DEFINE _D2orD3}');
L.Add(' {$DEFINE _D2orD3orD4}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFDEF VER100} // Delphi 3');
L.Add(' {$DEFINE _D3}');
L.Add(' {$DEFINE _D3orHigher}');
L.Add(' {$DEFINE _D2orD3}');
L.Add(' {$DEFINE _D2orD3orD4}');
L.Add(' {$DEFINE _D3orD4}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFDEF VER120} // Delphi 4');
L.Add(' {$DEFINE _D3orHigher}');
L.Add(' {$DEFINE _D3orD4}');
L.Add(' {$DEFINE _D4}');
L.Add(' {$DEFINE _D4orHigher}');
L.Add(' {$DEFINE _D2orD3orD4}');
L.Add(' {$IFnDEF KOL_MCK}');
L.Add(' {$DEFINE INPACKAGE}');
L.Add(' {$ENDIF}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFDEF VER130} // Delphi 5');
L.Add(' {$DEFINE _D3orHigher}');
L.Add(' {$DEFINE _D4orHigher}');
L.Add(' {$DEFINE _D5}');
L.Add(' {$DEFINE _D5orHigher}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{--- Delphi 6 and above -----------------------------------------------------}');
L.Add('{$IFDEF CONDITIONALEXPRESSIONS}');
L.Add(' // These version-specific symbols are always true for D6+');
L.Add(' {$DEFINE _D3orHigher}');
L.Add(' {$DEFINE _D4orHigher}');
L.Add(' {$DEFINE _D5orHigher}');
L.Add('');
SetLength(cumulativeHigher, 0);
for i := 0 to High(KnownVersions) do
begin
// extend the cumulative "orHigher" list with this version's own higher-defines
for j := 0 to High(KnownVersions[i].HigherDefines) do
begin
SetLength(cumulativeHigher, Length(cumulativeHigher) + 1);
cumulativeHigher[High(cumulativeHigher)] := KnownVersions[i].HigherDefines[j];
end;
L.Add(Format(' {$IFDEF VER%d} // %s', [KnownVersions[i].VerNum, KnownVersions[i].Comment]));
for d in KnownVersions[i].OwnDefines do
L.Add(Format(' {$DEFINE %s}', [d]));
for d in cumulativeHigher do
L.Add(Format(' {$DEFINE %s}', [d]));
L.Add(' {$ENDIF}');
L.Add('');
end;
L.Add(' {--- Warning settings for D7+ (was {$IF CompilerVersion >= 15}) ---------}');
L.Add(' {$IFDEF _D7orHigher}');
L.Add(' {$WARN UNIT_DEPRECATED OFF}');
L.Add(' {$WARN SYMBOL_PLATFORM OFF}');
L.Add(' {$WARN UNSAFE_TYPE OFF}');
L.Add(' {$WARN UNSAFE_CAST OFF}');
L.Add(' {$WARN UNSAFE_CODE OFF}');
L.Add(' {$ENDIF}');
L.Add('');
L.Add(' {--- Delphi 2005+ (D8): inline off (was {$IF CompilerVersion >= 17}) ----}');
L.Add(' {$IFDEF _D2005orHigher}');
L.Add(' {$INLINE OFF}');
L.Add(' {$ENDIF}');
L.Add('');
L.Add(' {--- Stripping relocations, D2006+ (was {$IF CompilerVersion >= 18}) ----}');
L.Add(' {$IFDEF _D2006orHigher}');
L.Add(' {$IFNDEF NO_STRIP_RELOC}');
L.Add(' {$SetPEFlags 1}');
L.Add(' {$ENDIF}');
L.Add(' {$ENDIF}');
L.Add('');
L.Add(' {--- Platform specific, XE2+ WIN64 (was {$IF CompilerVersion >= 23}) ----}');
L.Add(' {$IFDEF _DXE2orHigher}');
L.Add(' {$IFDEF WIN64}');
L.Add(' {$DEFINE PAS_VERSION}');
L.Add(' {$DEFINE PAS_ONLY}');
L.Add(' {.$DEFINE UNICODE_CTRLS}');
L.Add(' {$DEFINE STREAM_LARGE64}');
L.Add(' {$DEFINE TMSG_WINDOWS}');
L.Add(' {$ENDIF}');
L.Add(' {$ENDIF}');
L.Add('');
L.Add('{$ENDIF} // CONDITIONALEXPRESSIONS');
L.Add('');
L.Add('{--- Free Pascal (2.6+) -----------------------------------------------------}');
L.Add('{$IFDEF FPC}');
L.Add(' {$MODE DELPHI}');
L.Add(' {$DEFINE PAS_ONLY}');
L.Add(' {$DEFINE USE_OLD_FLAGS} // size of set type in fpc is 4 bytes');
L.Add('');
L.Add(' // TODO: extend per FPC version, same as the Delphi cascade above');
L.Add(' {$DEFINE _D3orHigher}');
L.Add(' {$DEFINE _D4orHigher}');
L.Add(' {$DEFINE _D5orHigher}');
L.Add(' {$DEFINE _D6orHigher}');
L.Add(' {$DEFINE _D7}');
L.Add(' {$DEFINE _D7orHigher}');
L.Add('');
L.Add(' {$UNDEF ASM_VERSION} // FPC typically uses Pascal only');
L.Add(' {$DEFINE PAS_VERSION}');
L.Add('{$ENDIF FPC}');
L.Add('');
L.Add('{--- KOL specific ----------------------------------------------------------}');
L.Add('{$IFNDEF _NOT_KOLCtrlWrapper_}');
L.Add(' {$DEFINE _KOLCtrlWrapper_}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{---- from delphidef.inc ---------------------------------------------------}');
L.Add('{$DEFINE ASM_VERSION} // Comment to produce Pascal code (or add PAS_VERSION)');
L.Add('{$IFDEF ASM_VERSION}');
L.Add(' {$IFDEF PAS_VERSION}');
L.Add(' {$UNDEF ASM_VERSION}');
L.Add(' {$ENDIF}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFNDEF _D6orHigher}');
L.Add(' {$DEFINE PARANOIA}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFNDEF USE_OLD_FLAGS}');
L.Add(' {$DEFINE USE_FLAGS}');
L.Add('{$ELSE}');
L.Add(' {$UNDEF USE_FLAGS}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFnDEF EVENTS_STATIC}');
L.Add(' {$DEFINE EVENTS_DYNAMIC}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$IFnDEF CMDACTIONS_RECORD}');
L.Add(' {$DEFINE COMMANDACTIONS_OBJ}');
L.Add(' {$DEFINE PACK_COMMANDACTIONS}');
L.Add(' {$IFDEF NOT_PACK_COMMANDACTIONS}');
L.Add(' {$UNDEF PACK_COMMANDACTIONS}');
L.Add(' {$ENDIF}');
L.Add('{$ENDIF}');
L.Add('');
L.Add('{$DEFINE KOL3XX}');
Result := L;
end;
procedure PrintUsage;
begin
Writeln('KolDefGen - regenerate koldef.inc with one new Delphi version added.');
Writeln;
Writeln('Usage:');
Writeln(' koldefgen <vernum> [shortname] [comment] [outputfile]');
Writeln;
Writeln('Example:');
Writeln(' koldefgen 370 _D13 "Delphi 13"');
Writeln;
Writeln('Currently known versions:');
end;
var
VerNum: Integer;
ShortName, Comment, OutputFile: string;
Lines: TStringList;
i: Integer;
begin
InitKnownVersions;
if (ParamCount < 1) or not TryStrToInt(ParamStr(1), VerNum) then
begin
PrintUsage;
for i := 0 to High(KnownVersions) do
Writeln(Format(' VER%-4d %s', [KnownVersions[i].VerNum, KnownVersions[i].Comment]));
Halt(1);
end;
if ParamCount >= 2 then
ShortName := ParamStr(2)
else
ShortName := Format('_DVER%d', [VerNum]);
if ParamCount >= 3 then
Comment := ParamStr(3)
else
Comment := Format('Delphi (VER%d)', [VerNum]);
if ParamCount >= 4 then
OutputFile := ParamStr(4)
else
OutputFile := 'koldef.inc';
try
AppendVersion(VerNum, ShortName, Comment);
Lines := BuildFile;
try
Lines.SaveToFile(OutputFile);
Writeln(Format('Wrote %s (added VER%d as %s / "%s")', [OutputFile, VerNum, ShortName, Comment]));
finally
Lines.Free;
end;
except
on E: Exception do
begin
Writeln('Error: ', E.Message);
Halt(1);
end;
end;
end.