Compiler Directives & Conditional Compilation

Directives are comments starting with $: {$R+}, {$MODE OBJFPC}, {$IFDEF DEBUG}.

23.1 Directive syntax

Directives are comments starting with $: {$R+}, {$MODE OBJFPC}, {$IFDEF DEBUG}. Switch directives use +/- or ON/OFF; parameter directives take a value; conditional directives control what is compiled.

23.2 Important switches

{$RANGECHECKS ON} array index and subrange checks {$OVERFLOWCHECKS ON} integer overflow checks {$IOCHECKS ON} I/O errors raise exceptions {$BOOLEVAL ON} full (non-short-circuit) Boolean evaluation {$LONGSTRINGS ON} string = long string on in Delphi, objfpc/delphi need it in FPC {$WRITEABLECONST ON} typed constants writable FPC on, Delphi off {$TYPEDADDRESS ON} @ returns typed pointers {$EXTENDEDSYNTAX ON} discard function results, PChar features {$ASSERTIONS ON} enable Assert Delphi on in debug {$TYPEINFO ON} generate RTTI for published members {$MINENUMSIZE 4} enum storage size (C compatibility) record field alignment {$INLINE ON} allow inline routines (FPC) on in objfpc/delphi {$POINTERMATH ON} pointer arithmetic on typed pointers (Delphi) {$SCOPEDENUMS ON} enum values must be qualified {$APPTYPE CONSOLE} console application (Windows) {$R file.res} link a resource file; {$R *.lfm} / {$R *.dfm} in forms

Local use pattern — enable a check only around a piece of code:

Delphi has no {$PUSH}/{$POP}; use {$IFOPT Q+}{$DEFINE QON}{$Q-}{$ENDIF} ... {$IFDEF QON}{$Q+}{$ENDIF}.

{$PUSH}{$R-}{$Q-}            // FPC: save current settings, then disable checks
function HashStr(const S: string): Cardinal;
var
  I: Integer;
begin
  Result := 2166136261;
  for I := 1 to Length(S) do
    Result := (Result xor Ord(S[I])) * 16777619;   // FNV-1a, overflow intended
end;
{$POP}

23.3 FPC modes and mode switches

default FPC dialect: TP-like, Integer = 16-bit, no classes {$mode objfpc}

Object Pascal, FPC flavor: classes, exceptions, Result, 32-bit Integer, @ needed for procvars, generic/specialize keywords {$mode delphi}

Delphi compatibility: Delphi generics syntax, no @ for procvars, advanced records {$mode delphiunicode} delphi + string = UnicodeString Turbo Pascal 7 compatibility {$mode macpas} Mac Pascal dialects

{$mode iso} / {$mode extendedpascal} ISO 7185 / ISO 10206 {$modeswitch advancedrecords} methods in records {$modeswitch typehelpers} helpers for primitive types {$modeswitch arrayoperators} + on dynamic arrays {$modeswitch nestedprocvars} is nested procedural types {$modeswitch prefixedattributes} Delphi-style [Attribute] syntax

{$modeswitch functionreferences}, {$modeswitch anonymousfunctions}

reference to and anonymous functions (FPC trunk/3.3.1+)

23.4 Conditional compilation

Define symbols on the command line (fpc -dDEBUG, or Delphi *Project → Options → Conditional defines*). {$UNDEF X} removes a symbol.

{$DEFINE VERBOSE}
{$IFDEF VERBOSE}
  Writeln('verbose mode');
{$ELSE}
  // quiet
{$ENDIF}

{$IFNDEF FPC}
  // Delphi-only code
{$ENDIF}

{$IF DEFINED(MSWINDOWS) OR DEFINED(WINDOWS)}
  Writeln('Windows');
{$ELSEIF DEFINED(LINUX)}
  Writeln('Linux');
{$ELSEIF DEFINED(DARWIN) OR DEFINED(MACOS)}
  Writeln('macOS');
{$ENDIF}

{$IFDEF FPC}
  {$IF FPC_FULLVERSION >= 30200}
    // uses features from FPC 3.2+
  {$ENDIF}
{$ELSE}
  {$IF CompilerVersion >= 36.0}
    // Delphi 12 Athens or later
  {$IFEND}
{$ENDIF}

23.5 Predefined symbols

compiled by Free Pascal VER3, VER3_2, VER3_2_2 numeric version (e.g. 30202) for {$IF} FPC_OBJFPC, FPC_DELPHI

WINDOWS, MSWINDOWS, WIN32, WIN64 Windows (MSWINDOWS is the Delphi-compatible one)

UNIX, LINUX, DARWIN, BSD, ANDROID POSIX, LINUX, MACOS, IOS, ANDROID

CPU386, CPUX86_64, CPUARM, CPUAARCH64, CPU64, CPU32

CPUX86, CPUX64, CPUARM, CPUARM64, CPU64BITS, CPU32BITS CompilerVersion, RTLVersion numeric constants: 35.0 = Delphi 11, 36.0 = Delphi 12 VER350, VER360 Delphi 11, Delphi 12 DEBUG, RELEASE defined by the build configuration {$IF} supported (Delphi 6+)

23.6 Messages and compile-time information

Warnings can be controlled per kind: {$WARN SYMBOL_DEPRECATED OFF} (Delphi), {$WARN 5024 OFF} (FPC message number, e.g. "parameter not used").

{$MESSAGE HINT 'Remember to remove debug code'}
{$WARNING 'Deprecated path'}         // FPC also: {$NOTE}, {$HINT}, {$ERROR}, {$FATAL}
{$IFNDEF CPU64}{$ERROR 'This unit requires a 64-bit target'}{$ENDIF}

const
  BuildDate = {$I %DATE%};           // FPC: compile-time date string
  FpcVer    = {$I %FPCVERSION%};     // FPC: compiler version string

23.7 Hint directives on declarations

The compiler warns wherever these are used.

procedure OldApi; deprecated 'Use NewApi instead';
procedure WindowsOnly; platform;
procedure Prototype; experimental;

🧪 Part II Exercises

Write overloaded Average functions for an open array of Integer and an open array of Double; add a default parameter that controls whether zeros are ignored.

Implement Swap, MinMax(const A: array of Integer; out Min, Max: Integer), and a generic-looking Apply that takes a procedural parameter; explain why each parameter uses value, var, const, or out.

Write recursive and iterative versions of Power(Base, Exp) (fast exponentiation by squaring) and compare their speed for large exponents.

Implement matrix addition, multiplication, and transposition for dynamic 2-D arrays (array of array of Double), with dimension checks that raise exceptions.

Model a library with records (TBook with title, author, year, ISBN) stored in a dynamic array; implement add, search by author, and sort by year.

Build a variant record TValue that can hold an integer, a real, or a Boolean, with a function that prints any TValue.

Use sets to implement a simple lexer that classifies characters into letters, digits, operators, and whitespace, and counts tokens in a line.

Implement a doubly linked list with insert-after, delete, reverse, and print-backwards operations; verify no leaks with fpc -gh (heaptrc).

Create a unit BankAccounts with an interface exposing Deposit, Withdraw, and Balance, a custom exception EInsufficientFunds, and an initialization section; use it from a console program that saves accounts to a typed file.

Write a program that copies a file using TFileStream, reports progress every 10%, and handles missing files with try/except; add {$IFDEF DEBUG} logging that you enable with -dDEBUG.