Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Language Atlas (mini-courses for more languages)  Module 4 – Object Pascal with Free Pascal (Delphi-compatible)

Object Pascal setup: FPC, modes and Delphi

Install the FPC 3.2.2 compiler, build a first Object Pascal program, choose objfpc or delphi mode, switch on range checks and see where Delphi fits.

  • Beginner
  • 20 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7 and fpc 3.2.2
  • By MySmartCoPilot
Free lesson, Pro answers: 20 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Install FPC 3.2.2 in a folder you own and compile and run a program from the command line
  • Choose a compiler mode for a file, objfpc or delphi, and know what each makes of Integer and string
  • Predict which setting wins when fpc.cfg, the command line and the file disagree
  • Switch on range and overflow checks and explain what {$Q+} alone misses on a 64-bit CPU
  • Explain how Free Pascal, Lazarus and Delphi relate and what the licence asks of your programs

Before you start

What you’ll learn · Before you start

What you will learn

  • Install FPC 3.2.2 in a folder you own and compile and run a program from the command line
  • Choose a compiler mode for a file, objfpc or delphi, and know what each makes of Integer and string
  • Predict which setting wins when fpc.cfg, the command line and the file disagree
  • Switch on range and overflow checks and explain what {$Q+} alone misses on a 64-bit CPU
  • Explain how Free Pascal, Lazarus and Delphi relate and what the licence asks of your programs

Before you start

On this page

A Free Pascal program that adds 1 to 2,147,483,647 prints −2,147,483,648 without a word, because the checks that would stop it are off until you switch them on, and on a 64-bit Mac the overflow check alone still lets this one through. Object Pascal is the language of Delphi and Lazarus, and Free Pascal 3.2.2 is the open-source compiler that runs every example of this mini-course, here on a Mac with Apple silicon; it is released for Windows and Linux too.

Here you install the compiler in a folder of your own and read what its first build prints. You choose between its two main dialects, objfpc and delphi, predict which setting wins when the configuration file, the command line and the file itself disagree, switch on the checks that stop a mark of 101, and see how Free Pascal, Lazarus and Delphi relate.

For macOS the Free Pascal download page offers an installer disk image, fpc-3.2.2.intelarm64-macosx.dmg, and the release’s own folder for Apple silicon, aarch64-darwin, also holds a plain tarball, fpc-3.2.2.aarch64-darwin.tar, which this mini-course installs. The project’s home page calls 3.2.2 the latest stable version; development versions are numbered 3.3.x. The tarball holds an installer script, install.sh, which asks where to install. The User’s Guide points out that the tar file lets you install below your home folder when you have no root rights, and the macOS download notes add that the compiler needs Apple’s Command Line Tools, whose linker it calls. Step through the whole path, from the download to a running program, with the two checks that can send you back:

Interactive · stage by stage From the release tarball to a running program Step through installing Free Pascal 3.2.2 into a folder you own and building a first program, with the two ways back when a check fails.
From the release tarball to a running program, step 9 of 9. Showing Download the release, Check its SHA-256, Run install.sh, Ask fpc -iV, Compile hello.pas, Link with Apple's ld, Run ./hello. In focus: Run ./hello.hash differsnot 3.2.2Download the releaseaarch64-darwin tarballCheck its SHA-256starts 70e93eefRun install.shprefix: a folder you ownAsk fpc -iVthe pin is 3.2.2Compile hello.pasoptions from fpc.cfgLink with Apple's ldtwo linker warningsRun ./hello1,053,720 bytes

The drawing shows the whole scene; its 9 steps are listed below.

Every step as text
  1. Download the release. For macOS the download page offers a disk image, and the release folder for Apple silicon also holds the tarball fpc-3.2.2.aarch64-darwin.tar, about 100 MB, with install.sh and the compiler packages inside. This mini-course installs the tarball.
  2. Check the file. shasum -a 256 prints the SHA-256 of the file. The tarball this lesson's runs used has one that starts 70e93eef; a different hash means a different or damaged file, so download it again before you run anything from it.
  3. Hash differs. A mismatch sends you back to the download. Run install.sh only from a file whose hash matches.
  4. Install into a prefix. Unpack the tarball and run ./install.sh from its folder. It asks where to install; a folder you own, such as ~/fpc-3.2.2, needs no administrator rights. Without write access to /etc it writes its configuration to ~/.fpc.cfg.
  5. Ask for the version. Put the prefix's bin folder on your PATH and ask fpc -iV. It must answer 3.2.2, as it did in the recorded session; fpc -iTP answered aarch64 and fpc -iTO darwin.
  6. Another fpc first. Any other answer means another Free Pascal comes first on your PATH. Fix the PATH, or call the one in your prefix by its full path, before you compare any output.
  7. Compile. fpc hello.pas calls the real compiler, ppca64, which reads its options from fpc.cfg and compiles the 13 lines into an object file. The banner, Compiling and Assembling lines are its progress.
  8. Link. On macOS the compiler hands the object files to Apple's linker from the Command Line Tools. It prints two warnings about options that Free Pascal 3.2.2 still passes; the program is not affected.
  9. Run. ./hello prints its three lines, including the compiler version and target that the compiler filled in. The sample configuration strips debug information, so the program is 1,053,720 bytes.

The recorded session starts at the fourth stage, with the compiler installed. Here is the program it builds. The three values between % signs are filled in by the compiler, so the program reports what built it:

hello.pas, a first Object Pascal program PAS · hello.pas
program Hello;
{ A first Object Pascal program. The compiler fills in the three %FPC...% values
  while it compiles, so the program reports the compiler and the target it was built for. }
{$mode objfpc}{$H+}

uses
  SysUtils;

begin
  WriteLn(Format('Hello from Free Pascal %s', [{$I %FPCVERSION%}]));
  WriteLn(Format('Built for %s on %s', [{$I %FPCTARGETCPU%}, {$I %FPCTARGETOS%}]));
  WriteLn(Format('%d + %d = %d', [40, 2, 40 + 2]));
end.

Each command of the session follows a $, and the lines below it are what the command printed:

Version, target, a first build and the configuration file it read Python · setup_session.py
from session import run

# The first session of the Object Pascal mini-course: ask the compiler for its version and target, then build and
# run a first program with the default output, read the size of what was built, see which configuration file the
# compiler read, build once more without the banner and the progress lines, and once with smart linking (-XX).
run("""
fpc -iV
fpc -iTP
fpc -iTO
fpc hello.pas
./hello
wc -c < hello
fpc -vt hello.pas 2>&1 | grep -e 'Configfile search' -e 'Reading options'
fpc -l- -vi- hello.pas
fpc -l- -vi- -XX hello.pas -ohello_small
./hello_small
wc -c < hello_small
""")

Output

$ fpc -iV
3.2.2
$ fpc -iTP
aarch64
$ fpc -iTO
darwin
$ fpc hello.pas
Free Pascal Compiler version 3.2.2 [2022/10/19] for aarch64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Darwin for AArch64
Compiling hello.pas
Assembling hello
Linking hello
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
13 lines compiled, … sec
$ ./hello
Hello from Free Pascal 3.2.2
Built for aarch64 on Darwin
40 + 2 = 42
$ wc -c < hello
 1053720
$ fpc -vt hello.pas 2>&1 | grep -e 'Configfile search' -e 'Reading options'
Configfile search: ~/.fpc.cfg
Configfile search: …/etc/fpc.cfg
Reading options from file …/etc/fpc.cfg
$ fpc -l- -vi- hello.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ fpc -l- -vi- -XX hello.pas -ohello_small
ld: warning: option '-no_dead_strip_inits_and_terms' is obsolete, use '-dead_strip' instead
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./hello_small
Hello from Free Pascal 3.2.2
Built for aarch64 on Darwin
40 + 2 = 42
$ wc -c < hello_small
  223496

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 setup_session.py

Read it from the top. fpc -iV prints the short version, 3.2.2, the toolchain pin: The exact version of the compiler, interpreter or SDK that an example was built and run with, such as Tcl 9.0.4 or the .NET SDK 10.0.401. Another version may print something else for the same file. More in “How the Language Atlas works” of every example in this mini-course, and -iTP and -iTO print the target processor and system, aarch64 and darwin. The first build shows the compiler’s banner, the target, one line per step (Compiling, Assembling, Linking) and the number of lines compiled, 13. The two lines before that count come from Apple’s linker, which objects to two options that Free Pascal 3.2.2 still passes to it. The program is not affected, and the same two lines follow every build in this mini-course.

The compiler took most of its options from a configuration file, fpc.cfg. With -vt it lists where it looked: first ~/.fpc.cfg in your home folder, then …/etc/fpc.cfg, the etc folder above the compiler’s bin folder (… is the folder you installed into), and it read the second. The User’s Guide gives the full order on Unix-like systems: the current folder, ~/.fpc.cfg, the folder named by PPC_CONFIG_PATH, the etc folder above the compiler, then /etc. The first file found is the one used. install.sh writes ~/.fpc.cfg when it cannot write to /etc.

The program is 1,053,720 bytes, already without debug information: the sample configuration adds -Xs, which strips it. Units are linked in whole by default, and with -XX, smart linking, only the parts the program calls are kept; the same program came to 223,496 bytes, about a fifth, and the linker added a third warning of the same kind. The last builds pass -l- and -vi-, which leave out the banner and the progress lines, so only the linker’s lines remain. The later lessons of this mini-course build that way.

Repeat the first build

With Free Pascal 3.2.2 installed and its bin folder on your PATH, save the program as hello.pas and type fpc -iV, then fpc hello.pas, then ./hello. On another version or another platform the banner and the target lines differ, and the three lines the program prints name what built it.

Checkpoint

Check: Installing Free Pascal and reading a first build

  1. Question 1 of 2 install.sh wrote ~/.fpc.cfg for you. A colleague then adds -Cr to the fpc.cfg in the etc folder above the compiler. Does your next build get range checks?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: No: the compiler uses the first configuration file it finds, and ~/.fpc.cfg comes first

    Free Pascal looks for one configuration file: in the current folder, then ~/.fpc.cfg, then the folder in PPC_CONFIG_PATH, then the etc folder above the compiler, then /etc. The first one it finds is used, so an option added to a file further down the list has no effect while ~/.fpc.cfg exists.

  2. Question 2 of 2 Which options left out the compiler's banner and its progress lines in the session?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: -l- -vi-

    The later builds of the session, and of this mini-course, use fpc -l- -vi- file.pas. Errors, warnings and notes still appear; only the banner and the progress lines go.

The mode decides which Pascal the compiler reads

Compile a short program with a class in it and no mode directive, and Free Pascal stops at the first line that uses the word: Identifier not found "class". The same file compiles with -Mobjfpc. Free Pascal reads several dialects of Pascal, and the compiler mode: The dialect a Free Pascal file is compiled in, chosen with {$mode …} in the file or -M on the command line: fpc (the default), objfpc, delphi, delphiunicode, tp and others. The mode decides, among other things, whether class is a keyword and how big an Integer is. chooses one. In the default, fpc mode, class is not a keyword, an Integer has 16 bits and a string is a ShortString: Pascal's original string type: at most 255 characters, kept with a length byte in a fixed block of 256 bytes. In Free Pascal the word string means ShortString unless {$H+} is in force. of at most 255 characters; objfpc mode switches on classes, exceptions and interfaces. The session shows the class failing, then one program in four modes, and one generic record written the objfpc way and the delphi way:

A class without a mode, one program in four modes, and generic syntax Python · modes_session.py
from session import run

# A class without a mode directive, in the default mode and in objfpc mode; one program compiled in four modes;
# the same generic record in objfpc and in delphi syntax; and delphi syntax under {$mode objfpc}, which does not
# compile.
run("""
cd modes
!fpc -l- -vi- no_mode.pas
fpc -l- -vi- -Mobjfpc no_mode.pas
./no_mode
fpc -l- -vi- sizes.pas -osizes_fpc
./sizes_fpc
fpc -l- -vi- -Mobjfpc sizes.pas -osizes_objfpc
./sizes_objfpc
fpc -l- -vi- -Mdelphi sizes.pas -osizes_delphi
./sizes_delphi
fpc -l- -vi- -Mdelphiunicode sizes.pas -osizes_unicode
./sizes_unicode
fpc -l- -vi- pair_objfpc.pas
./pair_objfpc
fpc -l- -vi- pair_delphi.pas
./pair_delphi
!fpc -l- -vi- pair_wrong.pas
""")

Output

$ cd modes
$ fpc -l- -vi- no_mode.pas
no_mode.pas(4,14) Error: Identifier not found "class"
no_mode.pas(5,5) Error: Error in type definition
no_mode.pas(5,5) Fatal: Syntax error, ";" expected but "identifier NAME" found
Fatal: Compilation aborted
Error: …/bin/ppca64 returned an error exitcode
[exit status 1]
$ fpc -l- -vi- -Mobjfpc no_mode.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./no_mode
a class, compiled in objfpc mode: Asha
$ fpc -l- -vi- sizes.pas -osizes_fpc
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./sizes_fpc
SizeOf(Integer) = 2, High(Integer) = 32767
SizeOf(String) = 256, SizeOf(Char) = 1
$ fpc -l- -vi- -Mobjfpc sizes.pas -osizes_objfpc
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./sizes_objfpc
SizeOf(Integer) = 4, High(Integer) = 2147483647
SizeOf(String) = 256, SizeOf(Char) = 1
$ fpc -l- -vi- -Mdelphi sizes.pas -osizes_delphi
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./sizes_delphi
SizeOf(Integer) = 4, High(Integer) = 2147483647
SizeOf(String) = 8, SizeOf(Char) = 1
$ fpc -l- -vi- -Mdelphiunicode sizes.pas -osizes_unicode
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./sizes_unicode
SizeOf(Integer) = 4, High(Integer) = 2147483647
SizeOf(String) = 8, SizeOf(Char) = 2
$ fpc -l- -vi- pair_objfpc.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./pair_objfpc
objfpc: Asha 72, Ravi 58
$ fpc -l- -vi- pair_delphi.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./pair_delphi
delphi: Asha 72, Ravi 58
$ fpc -l- -vi- pair_wrong.pas
pair_wrong.pas(6,8) Fatal: Syntax error, "=" expected but "<" found
Fatal: Compilation aborted
Error: …/bin/ppca64 returned an error exitcode
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 modes_session.py

SizeOf(Integer) is 2 in fpc mode and 4 in the others, so High(Integer) jumps from 32,767 to 2,147,483,647. SizeOf(String) is 256 bytes for a ShortString and 8, the size of a pointer, for the strings the Delphi modes use. In delphiunicode mode a Char takes 2 bytes, and string is a UnicodeString. The four modes this mini-course meets:

Mode Integer string A generic type
fpc, the default 16 bits ShortString written as in objfpc
objfpc 32 bits ShortString until {$H+} generic and specialize
delphi 32 bits AnsiString TPair<T>, no keywords
delphiunicode 32 bits UnicodeString TPair<T>, no keywords

Generics show the difference best. In objfpc mode a generic type is declared with generic and every use names a type with specialize; the Reference Guide says delphi mode must not use either keyword. The two modes also treat procedure variables differently: objfpc needs the address operator, @, to assign one, while delphi mode takes the routine’s plain name, as Delphi code writes it. objfpc is the default mode of Lazarus source files, and delphi mode is the one for code written for Delphi.

Delphi syntax under {$mode objfpc}

A file that starts with {$mode objfpc} and declares TPair<T> = record does not compile: Free Pascal stopped with Syntax error, "=" expected but "<" found. Write generic TPair<T> = record and specialize TPair<Integer>, or start the file with {$mode delphi} if it was written for Delphi.

Which mode a file should start with depends on where its code comes from and where it will live. Answer the three questions and the table marks what fits:

Interactive · answer and compare Which mode should a file start with? Answer three questions about the code you are about to compile. The table marks the modes that fit and says why the others do not.
Where does the code come from?
Must string hold 2-byte UTF-16 characters, as in a Delphi whose string is a UnicodeString?
Will the file live in a Lazarus project next to the units Lazarus creates?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Four Free Pascal modes against the four things that decide between them
Mode Code written for Delphi Integer What string means New Lazarus units
objfpc Selected with: {$mode objfpc}{$H+} Mixed generics need generic and specialize, and procedure variables need @ Good 32 bits, as in delphi mode Mixed ShortString unless {$H+} follows the mode directive Good the default mode of Lazarus source files
delphi Selected with: {$mode delphi} Good emulates Delphi: TPair<T> without generic or specialize Good 32 bits Good AnsiString: the mode implies {$H+} Mixed compiles in Lazarus, but its units start in objfpc mode
delphiunicode Selected with: {$mode delphiunicode} Good delphi mode with string as a UnicodeString Good 32 bits Mixed UnicodeString: SizeOf(Char) is 2 in the recorded run Mixed compiles, but string differs from the objfpc units around it
fpc, the default Selected with: no mode directive Poor class is not a keyword: no_mode.pas did not compile Poor 16 bits: High(Integer) is 32767 Poor ShortString: at most 255 characters Poor no classes, so no forms or components
How the answers decide
  • “Where does the code come from?” It was written for Delphi: rules out fpc, the default and adds a caveat to objfpc. Delphi code needs classes and 32-bit Integers; under objfpc its generics and procedure variables need edits first.
  • “Where does the code come from?” It is new, or written for Free Pascal: rules out fpc, the default. The default fpc mode has no classes and a 16-bit Integer, so new Object Pascal code starts with a mode directive.
  • “Must string hold 2-byte UTF-16 characters, as in a Delphi whose string is a UnicodeString?” Yes, the code expects UnicodeString: adds a caveat to objfpc and delphi. Here string is an AnsiString of 1-byte characters; only delphiunicode makes string a UnicodeString.
  • “Must string hold 2-byte UTF-16 characters, as in a Delphi whose string is a UnicodeString?” No, 1-byte characters are fine: adds a caveat to delphiunicode. Every string becomes a UnicodeString of 2-byte characters, which code that expects bytes does not want.
  • “Will the file live in a Lazarus project next to the units Lazarus creates?” Yes, in a Lazarus project: adds a caveat to delphi and delphiunicode. Lazarus source files use objfpc mode by default; another mode works, but differs from the units around it.

In short: {$mode objfpc}{$H+} for new code and for Lazarus, {$mode delphi} for code written for Delphi, and {$mode delphiunicode} only when that code expects string to hold 2-byte characters.

Checkpoint

Check: What a compiler mode changes

  1. Question 1 of 2 sizes.pas has no mode directive. Built with plain fpc sizes.pas, what does it print for High(Integer)?

    Type a number.

    A hint

    Without a mode directive or -M option the compiler is in its default mode. How many bits does Integer have there?

    Show the answer: Question 1 of 2

    Answer: 32767 printed

    The default fpc mode keeps the 16-bit Integer of older Pascals, so SizeOf(Integer) is 2 and High(Integer) is 32767. objfpc, delphi and delphiunicode load the Objpas unit, which makes Integer 32 bits: 2147483647.

  2. Question 2 of 2 A file starts with {$mode objfpc}{$H+} and needs a record that holds two values of one type. Which declaration compiles?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: generic TPair<T> = record First, Second: T; end; and then TMarkPair = specialize TPair<Integer>;

    Generics are the clearest difference between the two modes: objfpc writes generic and specialize, and the Reference Guide says delphi mode must not use either keyword.

The last setting wins, and a mode resets {$H}

The program mode_and_r.pas starts with {$mode objfpc} and {$R-}, and it prints the settings it was compiled with. Built with fpc -Mdelphi -Sh -Cr, it printed objfpc mode, a ShortString and range checks off: none of the three options survived. The compiler reads its settings in a fixed order, the configuration file first, then the command line from left to right, then the file’s own compiler directive: An instruction to the compiler written in the source, in braces that start with a dollar sign, such as {$mode objfpc} or {$R+}. It applies from the point where it appears, and it replaces the same setting given in fpc.cfg or on the command line. from top to bottom, and a later setting replaces an earlier one. Step through that build:

Interactive · stage by stage How fpc -Mdelphi -Sh -Cr mode_and_r.pas ends up in objfpc mode Step through the settings in the order the compiler reads them and watch which ones survive to the end.
How fpc -Mdelphi -Sh -Cr mode_and_r.pas ends up in objfpc mode, step 8 of 8. Showing Built-in defaults, fpc.cfg, -Mdelphi (mode delphi · H on), -Sh (H on), -Cr (R on), {$mode objfpc} (mode objfpc · H off), {$R-} (R off), What the program printed. In focus: What the program printed.Built-in defaultsfpc · H off · R offfpc.cfgsets none of the three-Mdelphimode delphi · H on-ShH on-CrR on{$mode objfpc}mode objfpc · H off{$R-}R offWhat the program printedobjfpc · H off · R off

The drawing shows the whole scene; its 8 steps are listed below.

Every step as text
  1. Start. Before it reads anything, the compiler is in fpc mode, where string is a ShortString, and range checks are off.
  2. The configuration file. fpc.cfg is read first. The sample configuration sets search paths, the banner and the messages, but no mode and no checks, so nothing changes here.
  3. -Mdelphi. The command line comes next, left to right. -Mdelphi selects delphi mode, and selecting a mode also sets {$H}: delphi mode switches it on.
  4. -Sh. -Sh switches {$H} on. It already was, so string is still an AnsiString.
  5. -Cr. -Cr switches range checks on. After the command line the build would be delphi mode, AnsiString, range checks on.
  6. The file's mode. Then the file, top to bottom. {$mode objfpc} replaces delphi mode, and like every mode it resets {$H}: objfpc switches it off, so the -Sh from the command line is gone.
  7. {$R-}. {$R-} switches range checks off, replacing -Cr. A setting in the file always comes after the command line, so the file wins.
  8. The result. The program printed mode: objfpc, string: ShortString and range checks: off. None of the three command-line options survived.

The surprising step is the sixth: a mode directive also sets {$H}. The Programmer’s Guide says a delphi mode directive implies {$H+} and all other modes switch it off (delphiunicode, which that page does not name, switched it on too in sizes.pas), and it draws the conclusion itself:

As a result, you should always put {$H+} after a mode directive.

The same two lines in the other order show what happens when you do not:

{$H+} before and after the mode directive, and a file that overrides the command line Python · order_session.py
from session import run

# The order of the settings: {$H+} before and after the mode directive, then options on the command line that the
# file's own directives override.
run("""
cd order
fpc -l- -vi- h_before_mode.pas
./h_before_mode
fpc -l- -vi- h_after_mode.pas
./h_after_mode
fpc -l- -vi- -Mdelphi -Sh -Cr mode_and_r.pas
./mode_and_r
""")

Output

$ cd order
$ fpc -l- -vi- h_before_mode.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./h_before_mode
mode: objfpc
string: ShortString, at most 255 characters
range checks: off
$ fpc -l- -vi- h_after_mode.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./h_after_mode
mode: objfpc
string: AnsiString
range checks: off
$ fpc -l- -vi- -Mdelphi -Sh -Cr mode_and_r.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./mode_and_r
mode: objfpc
string: ShortString, at most 255 characters
range checks: off

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 order_session.py

h_before_mode.pas asked for {$H+} and got a ShortString, because the mode directive on the next line switched it off again. h_after_mode.pas got its AnsiString. A mode does not reset range or overflow checks: in the next section -Cr -Co stay on through the {$mode objfpc} of the file they build. So write the pair in this order, {$mode objfpc}{$H+}, at the top of every unit and program for objfpc mode.

Key idea

Settings are read in order, fpc.cfg, then the command line, then the file, and the last one wins; a mode directive resets {$H}, so {$H+} goes after it.

Checkpoint

Check: The order of settings and the {$H} reset

  1. Question 1 of 2 A build script runs fpc -Mdelphi -Cr report.pas, and report.pas starts with {$mode objfpc} and {$R-}. Which settings does the program get?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: objfpc mode, range checks off

    Free Pascal reads fpc.cfg, then the command line from left to right, then the file from top to bottom. A directive in the file therefore overrides the same setting given on the command line.

  2. Question 2 of 2 A program has {$H+} on line 2 and {$mode objfpc} on line 3. What does string mean in it?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: ShortString, at most 255 characters

    The Programmer's Guide says a delphi mode directive implies {$H+} and every other mode switches it off, and so tells you to put {$H+} after the mode directive.

Range and overflow checks are off until you switch them on

marks.pas declares a mark as the subrange 0..100 and stores 101 in it. Built as it is, it printed stored mark: 101: nothing checks a subrange unless range checking: Code the compiler adds, with {$R+} or -Cr, that stops a program when a value leaves its declared range, such as 101 stored in a 0..100 subrange or an array index past the end. Free Pascal leaves it off unless you switch it on. is on, and the Programmer’s Guide says it is off by default. Built with -Cr, the command-line form of {$R+}, the same program stopped with Runtime error 201 and exit status 201, as the guide describes. The overflow program then tries the two classic overflows under each combination of checks:

A mark of 101, and two overflows under each combination of checks Python · checks_session.py
from session import run

# Range and overflow checks, off by default: a subrange that accepts 101, then the same overflow program built
# without checks, with -Co ({$Q+}), with -Cr ({$R+}) and with both.
run("""
cd checks
fpc -l- -vi- marks.pas
./marks
fpc -l- -vi- -Cr marks.pas
!./marks
fpc -l- -vi- overflow.pas -ooverflow_none
./overflow_none
fpc -l- -vi- -Co overflow.pas -ooverflow_q
./overflow_q
fpc -l- -vi- -Cr overflow.pas -ooverflow_r
./overflow_r
fpc -l- -vi- -Cr -Co overflow.pas -ooverflow_rq
./overflow_rq
""")

Output

$ cd checks
$ fpc -l- -vi- marks.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./marks
stored mark: 101
$ fpc -l- -vi- -Cr marks.pas
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./marks
Runtime error 201 at $…
  $…
[exit status 201]
$ fpc -l- -vi- overflow.pas -ooverflow_none
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./overflow_none
Integer: 2147483647 + 1 = -2147483648
Int64:   High(Int64) + 1 = -9223372036854775808
$ fpc -l- -vi- -Co overflow.pas -ooverflow_q
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./overflow_q
Integer: 2147483647 + 1 = -2147483648
Int64:   EIntOverflow: Arithmetic overflow
$ fpc -l- -vi- -Cr overflow.pas -ooverflow_r
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./overflow_r
Integer: ERangeError: Range check error
Int64:   High(Int64) + 1 = -9223372036854775808
$ fpc -l- -vi- -Cr -Co overflow.pas -ooverflow_rq
-macosx_version_min has been renamed to -macos_version_min
ld: warning: -multiply_defined is obsolete
$ ./overflow_rq
Integer: ERangeError: Range check error
Int64:   EIntOverflow: Arithmetic overflow

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 checks_session.py

The four builds of overflow.pas, side by side:

Build High(Integer) + 1 in an Integer High(Int64) + 1
no checks −2,147,483,648 −9,223,372,036,854,775,808
-Co, overflow checks −2,147,483,648 EIntOverflow
-Cr, range checks ERangeError −9,223,372,036,854,775,808
-Cr -Co, both ERangeError EIntOverflow

The second row is the surprise: overflow checking: Code the compiler adds, with {$Q+} or -Co, that stops a program when integer arithmetic overflows. On a 64-bit CPU Free Pascal computes 32-bit expressions in 64 bits, so a 32-bit overflow is caught by range checking instead. alone let the 32-bit overflow through. The Programmer’s Guide explains why. On 64-bit CPUs integer expressions are computed with 64-bit integers, so the sum of 2,147,483,647 and 1 is no overflow at all; it only goes wrong when the result is stored in a 32-bit variable, and that is a range error, which -Cr catches. The Int64 sum overflows the 64 bits themselves, so only -Co sees it. Programs that use SysUtils turn these run-time errors into exceptions, such as ERangeError and EIntOverflow, which a handler can catch. A program without SysUtils, like marks.pas, stops with the error’s number.

Number Base Converter Convert 2147483647 to hexadecimal, 7FFFFFFF, to see the largest 32-bit Integer, and why one more wraps to −2147483648.

Switch both checks on while you learn and wherever a wrong number costs more than a check: put {$R+}{$Q+} after the mode directive, or build with -Cr -Co. The sample configuration does part of this for you: building with -dDEBUG selects its debug section, which adds -Crtoi (range, overflow, stack and input-output checks).

Checkpoint

Check: Range and overflow checks on a 64-bit CPU

  1. Question 1 of 2 On an Apple silicon Mac, a program built with -Co only runs total := High(Integer); next := total + 1; where both are Integers. What happens?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: next becomes -2147483648 and nothing reports it

    The build with -Co alone printed Integer: 2147483647 + 1 = -2147483648. The Programmer's Guide explains that on 64-bit CPUs 32-bit arithmetic cannot overflow and the error shows up as a range error on assignment, which only -Cr ({$R+}) catches.

  2. Question 2 of 2 marks.pas, built with -Cr, stores 101 in a 0..100 variable and stops. What exit status does the session show?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 201 exit status

    A range check that fails without SysUtils stops the program with Runtime error 201 and exit status 201, as the Programmer's Guide describes for {$R+}.

Free Pascal, Lazarus and Delphi share one language

A unit written in Object Pascal may have been written for one of three tools, and each reads it a little differently. Delphi is Embarcadero’s commercial IDE and compiler; its maker describes it as a way to build native applications for Windows, macOS, iOS, Android and Linux, with the VCL and FireMonkey component libraries. Free Pascal is the open-source compiler; the Lazarus team describes it as designed to understand and compile Delphi syntax, and it runs on many processors and systems. Lazarus is an open-source IDE for Free Pascal: its project page calls it a Delphi compatible cross-platform IDE, and its component library, the LCL, is more or less compatible with Delphi’s VCL. Lazarus 4.8, the release its download button offers, was built with Free Pascal 3.2.2, and with the 3.2.4 release candidate on macOS.

Object Pascal is compiled by Delphi, from Embarcadero, and by Free Pascal; Lazarus is an IDE built on Free Pascal.Object Pascalthe languageDelphiby EmbarcaderocommercialVCL, FireMonkeyFree Pascal 3.2.2open sourcecompiler: GPLRTL: modified LGPLLazarusan IDE onFree PascalLCL, close to VCLcompiled bycompiled bybuilds

One language, three tools

Text description of the diagram

The diagram is read from top to bottom.

  1. Object Pascal is the language, with units, classes, exceptions, generics and interfaces.
  2. Two compilers read it. Delphi, by Embarcadero, is a commercial IDE and compiler with the VCL and FireMonkey component libraries. Free Pascal 3.2.2 is open source: the compiler is under the GPL, and its run-time library (RTL) is under a modified LGPL.
  3. Lazarus is an open-source IDE for Free Pascal: Free Pascal builds every Lazarus project, and Lazarus adds the LCL, a component library close to Delphi's VCL.

The licences decide what you may do with the programs you build. The Free Pascal FAQ says the compiler is under the GPL, while programs that use the run-time library come under a modified LGPL with an exception that lets you distribute the program on terms of your choice: the licence imposes nothing on the programs you create, closed source included. What it still asks is about the library itself: the RTL’s source must be available to anyone who receives your program, which pointing to the Free Pascal website satisfies if you did not change the RTL, and changes you make to the RTL must be shared.

Where is the language used? Embarcadero sells Delphi for native applications on five systems, and the Lazarus site lists what people build with Lazarus, from file browsers and image viewers to database applications, games and medical analysis software. In the Stack Overflow Developer Survey 2025, 2.5 % of the people who answered its question on programming languages had done extensive development work in Delphi over the past year. Whether you meet the language in a Delphi codebase or a Lazarus project, it is the same language in two dialects, which is why this mini-course writes both.

Organisations named on this page

MySmartCoPilot has no link with Embarcadero, the Free Pascal and Lazarus teams or Stack Overflow. Each is named only as the maker or publisher of a tool, a document or a survey. Every example on this page was built with Free Pascal.

Checkpoint

Check: Free Pascal, Lazarus, Delphi and the licence

  1. Question 1 of 2 What is Lazarus?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: An open-source IDE for Free Pascal, with the LCL, a component library close to Delphi's VCL

    Delphi and Free Pascal are the two compilers of Object Pascal. Lazarus is the IDE built on Free Pascal, which calls itself a Delphi compatible cross-platform IDE.

  2. Question 2 of 2 You sell a closed-source program built with Free Pascal, and you did not change the run-time library. What does the RTL's licence ask of you?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: That the RTL's source is available to recipients, which pointing to the Free Pascal website satisfies

    The compiler is under the GPL; programs that use the RTL come under a modified LGPL with an exception that lets you distribute them on terms of your choice. Changes you make to the RTL itself must be made available.

Practise: work out which settings a build used

The exercise turns the order of the third section into code: given the options of a build and the directives at the top of its file, return the mode, what string means, the size of Integer and both checks. Its sample tests replay this lesson’s own builds, from sizes.pas in four modes to mode_and_r.pas built with -Mdelphi -Sh -Cr.

Exercise · Easy · Python

Work out which settings a Free Pascal build uses

A build script passes options to fpc, and the file starts with directives of its own. Before you trust a build, you want to know which settings it really used. Write effective(options, directives) in settings.py.

options is the list of command-line options in the order they were typed, such as ["-Mdelphi", "-Cr"]. directives is the list of directives at the top of the file, in the order they appear, such as ["{$mode objfpc}", "{$H+}"]. The function returns a dictionary with five keys:

  • "mode": "fpc", "objfpc", "delphi", "delphiunicode" or "tp", in lower case.
  • "string": what the word string means: "ShortString", "AnsiString" or "UnicodeString".
  • "integer_bits": 16 in the fpc and tp modes, 32 in the other three.
  • "range_checks" and "overflow_checks": True or False.

The rules, as the lesson's recorded builds showed them:

  • Before anything is read, the mode is fpc and {$H}, {$R} and {$Q} are all off.
  • The options are applied first, from left to right, then the directives, from top to bottom. A later setting replaces an earlier one, so the file's directives win over the command line.
  • -M<name> and {$mode <name>} set the mode. Setting a mode also sets {$H}: on for delphi and delphiunicode, off for every other mode. Names may be written in any case: -MOBJFPC and {$MODE DELPHI} work.
  • -Sh and {$H+} switch {$H} on; -Sh- and {$H-} switch it off. With {$H} off, string is a ShortString; with it on, string is a UnicodeString in delphiunicode mode and an AnsiString in every other mode.
  • -Cr and {$R+} switch range checks on, -Cr- and {$R-} off; -Co and {$Q+} switch overflow checks on, -Co- and {$Q-} off. A mode leaves both checks as they were.
  • Any other option, such as -O2 or -l-, changes none of the five settings. The letters of a directive may be in either case: {$h+} is {$H+}.

The sample tests replay the builds of the lesson, from sizes.pas in four modes to mode_and_r.pas built with -Mdelphi -Sh -Cr.

Starter code · settings.py

def effective(options, directives):
    """Return the mode, the meaning of string, the size of Integer and the two checks that a build uses."""
    # Replace these lines with your code: apply the options, then the directives.
    return {
        "mode": "fpc",
        "string": "ShortString",
        "integer_bits": 16,
        "range_checks": False,
        "overflow_checks": False,
    }
The sample tests · test_settings.py
from settings import effective


def test_default_mode():
    """sizes.pas built with no option: fpc mode, a 16-bit Integer and a ShortString"""
    assert effective([], []) == {"mode": "fpc", "string": "ShortString", "integer_bits": 16, "range_checks": False, "overflow_checks": False}


def test_modes_on_the_command_line():
    """sizes.pas built with -Mobjfpc, -Mdelphi and -Mdelphiunicode"""
    assert effective(["-Mobjfpc"], []) == {"mode": "objfpc", "string": "ShortString", "integer_bits": 32, "range_checks": False, "overflow_checks": False}
    assert effective(["-Mdelphi"], [])["string"] == "AnsiString"
    assert effective(["-Mdelphiunicode"], [])["string"] == "UnicodeString"
    assert effective(["-Mtp"], [])["integer_bits"] == 16


def test_h_before_the_mode_is_lost():
    """h_before_mode.pas: the mode directive switches {$H} off again"""
    assert effective([], ["{$H+}", "{$mode objfpc}"])["string"] == "ShortString"


def test_h_after_the_mode_stays():
    """h_after_mode.pas: {$H+} after the mode gives an AnsiString"""
    assert effective([], ["{$mode objfpc}", "{$H+}"])["string"] == "AnsiString"


def test_the_file_wins():
    """mode_and_r.pas built with -Mdelphi -Sh -Cr: the file's mode and {$R-} decide"""
    assert effective(["-Mdelphi", "-Sh", "-Cr"], ["{$mode objfpc}", "{$R-}"]) == {"mode": "objfpc", "string": "ShortString", "integer_bits": 32, "range_checks": False, "overflow_checks": False}


def test_a_mode_keeps_the_checks():
    """overflow.pas built with -Cr -Co: its {$mode objfpc}{$H+} leaves both checks on"""
    assert effective(["-Cr", "-Co"], ["{$mode objfpc}", "{$H+}"]) == {"mode": "objfpc", "string": "AnsiString", "integer_bits": 32, "range_checks": True, "overflow_checks": True}


def test_order_on_the_command_line():
    """-Sh before -Mobjfpc is undone by the mode; after it, it stays; -Sh- after -Mdelphi switches it off"""
    assert effective(["-Sh", "-Mobjfpc"], [])["string"] == "ShortString"
    assert effective(["-Mobjfpc", "-Sh"], [])["string"] == "AnsiString"
    assert effective(["-Mdelphi", "-Sh-"], [])["string"] == "ShortString"


def test_switching_off_and_any_case():
    """-Cr- and {$Q-} switch checks off; names and letters in any case; other options change nothing"""
    assert effective(["-Cr", "-Cr-", "-Co"], ["{$Q-}"])["range_checks"] is False
    assert effective(["-Co"], ["{$Q-}"])["overflow_checks"] is False
    assert effective(["-O2", "-l-", "-MOBJFPC"], ["{$h+}"]) == {"mode": "objfpc", "string": "AnsiString", "integer_bits": 32, "range_checks": False, "overflow_checks": False}
    assert effective([], ["{$MODE DELPHI}", "{$H-}"])["string"] == "ShortString"
A hint

Keep the four things that change in four variables (mode, {$H}, {$R}, {$Q}) and write one small function that sets a mode, because both -M<name> and {$mode <name>} must also reset {$H}. Read every option, then every directive, and only at the end turn the variables into the five answers.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Then work through the self-check, five ideas from fpc -iV to the licence. Ideas where your answers have slipped come up first, and every pick is explained the moment you make it:

Practice that adapts to you

Practise this lesson

16 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 16 Which command prints the short version of Free Pascal, to compare with the pin 3.2.2?

    Choose one answer.

    Show the answer: Question 1 of 16

    Answer: fpc -iV

    The -i options answer questions without building: V the short version, W the full one, TP and TO the target processor and system.

  2. Question 2 of 16 Every build on the Mac prints -macosx_version_min has been renamed to -macos_version_min and ld: warning: -multiply_defined is obsolete. What do you do about them?

    Choose one answer.

    Show the answer: Question 2 of 16

    Answer: Nothing: Apple's linker objects to two options that Free Pascal 3.2.2 passes, and the program is not affected

    On a Mac, Free Pascal links with Apple's linker from the Command Line Tools, which prints these two warnings for the options of older macOS versions that the compiler still passes. The lesson's programs all ran after them.

  3. Question 3 of 16 hello was 1,053,720 bytes. Which option made the same program 223,496 bytes?

    Choose one answer.

    Show the answer: Question 3 of 16

    Answer: -XX, smart linking

    Units are linked in whole by default. -XX links only what is used: the first program shrank to about a fifth of its size, 223,496 bytes.

  4. Question 4 of 16 In which mode of this lesson is Integer 16 bits wide?

    Choose one answer.

    Show the answer: Question 4 of 16

    Answer: fpc, the default mode

    fpc mode keeps the 16-bit Integer of older Pascals. The three Object Pascal modes of this lesson make it 32 bits.

  5. Question 5 of 16 What does the word string mean in delphi mode?

    Choose one answer.

    Show the answer: Question 5 of 16

    Answer: An AnsiString: delphi mode implies {$H+}

    delphi mode sets {$H+}, so string is an AnsiString. objfpc needs {$H+} written after its mode directive to get the same, and delphiunicode makes string a UnicodeString.

  6. Question 6 of 16 You must compile a large unit written for Delphi. It declares TList<Integer> without specialize and assigns procedure variables without @. Which first line saves the most edits?

    Choose one answer.

    Show the answer: Question 6 of 16

    Answer: {$mode delphi}

    Code written for Delphi compiles with the fewest changes in delphi mode, which emulates Delphi's syntax, generics and procedure variables included.

  7. Question 7 of 16 In which order does Free Pascal read its settings?

    Choose one answer.

    Show the answer: Question 7 of 16

    Answer: fpc.cfg, then the command line, then the directives in the file

    fpc.cfg, the command line from left to right, then the file from top to bottom: the last setting wins.

  8. Question 8 of 16 A build script runs fpc -Sh lazy.pas, and lazy.pas starts with {$mode objfpc} and nothing else. What is string?

    Choose one answer.

    Show the answer: Question 8 of 16

    Answer: ShortString: the file's mode directive switched {$H} off again

    A mode directive resets {$H}. To be sure of AnsiStrings, write {$H+} in the file after the mode directive.

  9. Question 9 of 16 Two scripts build a file without directives: one with fpc -Mobjfpc -Sh, the other with fpc -Sh -Mobjfpc. Which one gets AnsiStrings?

    Choose one answer.

    Show the answer: Question 9 of 16

    Answer: The first, -Mobjfpc -Sh

    The command line is read from left to right with the same rule as the file: a mode resets {$H}, so -Sh must follow -Mobjfpc.

  10. Question 10 of 16 With the default settings, what does storing 101 in a variable of type 0..100 do?

    Choose one answer.

    Show the answer: Question 10 of 16

    Answer: It stores 101, and the program goes on

    The Programmer's Guide says range checks are off unless you ask for them. With -Cr the same program stopped with Runtime error 201.

  11. Question 11 of 16 Which builds of overflow.pas stopped the Int64 sum High(Int64) + 1?

    Choose one answer.

    Show the answer: Question 11 of 16

    Answer: The builds with -Co, alone or together with -Cr

    -Co ({$Q+}) caught the 64-bit overflow; -Cr ({$R+}) caught the 32-bit one, on the assignment. Only the build with both caught both.

  12. Question 12 of 16 What does building with -dDEBUG do when the compiler reads the sample configuration?

    Choose one answer.

    Show the answer: Question 12 of 16

    Answer: It selects the configuration's debug section, which adds -Crtoi: range, overflow, stack and input-output checks

    -d defines a symbol, and the sample configuration's #IFDEF DEBUG section turns on debug information and four kinds of run-time checks for that build.

  13. Question 13 of 16 A marks report will run on 64-bit machines. Any total that overflows an Integer, and any mark outside 0..100, must stop it. What do you put after the mode directive?

    Choose one answer.

    Show the answer: Question 13 of 16

    Answer: {$R+}{$Q+}

    Range and overflow checks catch different things on a 64-bit CPU, so a program whose numbers matter switches on both.

  14. Question 14 of 16 Which tool is Embarcadero's commercial IDE and compiler for Object Pascal?

    Choose one answer.

    Show the answer: Question 14 of 16

    Answer: Delphi

    Two compilers read Object Pascal: Delphi from Embarcadero and the open-source Free Pascal, on which Lazarus is built.

  15. Question 15 of 16 Why does a Delphi form that uses only standard components have a chance of moving to Lazarus?

    Choose one answer.

    Show the answer: Question 15 of 16

    Answer: Lazarus's LCL is more or less compatible with Delphi's VCL, and Free Pascal reads Delphi syntax

    Free Pascal compiles Delphi syntax in delphi mode, and the LCL mirrors much of the VCL, so standard Delphi code can move; code that depends on Windows-only parts cannot.

  16. Question 16 of 16 Your team ships a closed-source tool built with Free Pascal, and it changed one unit of the RTL to fix a bug. What does the licence ask now?

    Choose one answer.

    Show the answer: Question 16 of 16

    Answer: Make the changed RTL source available to recipients who ask; your own code can stay closed

    The exception in the RTL's modified LGPL lets your program use any licence. The LGPL still covers the library: its source must be available, and your changes to it must be shared.

Interview questions

Warm-up (fresher to mid-level): What does {$mode objfpc}{$H+} at the top of a file do, and why in that order?

The first directive selects objfpc mode, the Free Pascal dialect with classes, exceptions and interfaces, in which an Integer has 32 bits; without a mode directive the compiler is in fpc mode, where class is not even a keyword. The second makes string an AnsiString, a reference-counted string of any length, instead of a ShortString of at most 255 characters. The order matters because setting a mode also sets {$H}: objfpc switches it off, so a {$H+} written before {$mode objfpc} is undone, and the file quietly gets ShortStrings. Directives in the file are read after fpc.cfg and the command line, so they also override -Sh or -M options given there. Write the pair in this order at the top of every unit and program for objfpc mode.

Two questions of the kind a team asks someone who will maintain Object Pascal code:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to senior

    A unit that has compiled in Delphi for years fails with Free Pascal 3.2.2 at its first class declaration. How do you get it building with Free Pascal, and how do you keep it building with both compilers afterwards?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A Pascal service stored a percentage of 101 and printed a negative total in production. Its release build had range and overflow checks off. What do you change, how do you show the change works, and what does it cost?

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. A Free Pascal program adds 1 to 2,147,483,647 with its checks left at their defaults. What does it print?

    −2,147,483,648, and nothing stops it: range and overflow checks stay off until you switch them on.

  2. Which fpc.cfg does the compiler read, and how can you see where it looked?

    The first one it finds, on a Mac ~/.fpc.cfg in the home folder before the etc folder above the compiler's bin folder. A build with -vt lists every place it tried.

  3. In Free Pascal's default fpc mode, how big is an Integer and what is a string?

    An Integer has 16 bits, so High(Integer) is 32,767, and string means ShortString, which holds up to 255 characters. class is not a keyword there: objfpc mode brings classes, exceptions and interfaces.

  4. How is a generic record written in objfpc mode, and in delphi mode?

    objfpc: generic TPair<T> = record, used as specialize TPair<Integer>. delphi: TPair<T> = record, with neither keyword, as Delphi code writes it.

  5. Why must {$H+} come after {$mode objfpc} and not before it?

    A mode directive sets {$H} as well, and objfpc turns it off. A {$H+} written first is undone, and string quietly stays a ShortString.

  6. A file starts with {$mode objfpc} and {$R-} and is built with fpc -Mdelphi -Sh -Cr. Which settings win?

    The file's: objfpc mode, ShortStrings and range checks off. The compiler reads fpc.cfg, then the command line, then the directives in the file, and a later setting replaces an earlier one.

  7. On a 64-bit CPU, which check stops High(Integer) + 1 from being stored in an Integer?

    Range checking, {$R+} or -Cr. The sum is worked out in 64 bits, where it does not overflow, and only storing it in 32 bits goes wrong, so {$Q+} alone lets it through.

  8. How do Delphi, Free Pascal and Lazarus relate?

    Delphi is Embarcadero's commercial IDE and compiler. Free Pascal is an open-source compiler that also reads Delphi syntax, and Lazarus is an open-source IDE built on Free Pascal. All three use Object Pascal.

Key takeaways

  • Free Pascal 3.2.2 installs from one release tarball into a folder you own, and fpc -iV must answer 3.2.2 before any output is compared; on a Mac it links with Apple’s linker, whose two warnings follow every build.
  • The compiler reads its options from the first configuration file it finds, ~/.fpc.cfg before the etc folder above its bin folder, and smart linking with -XX cut the first program from 1,053,720 to 223,496 bytes.
  • The mode decides the dialect: the default fpc mode has no classes and a 16-bit Integer, objfpc is the mode of new code and Lazarus, and delphi mode accepts Delphi syntax, generics included.
  • Settings are read as fpc.cfg, then the command line, then the file, and the last one wins; a mode directive resets {$H}, so {$H+} goes after it.
  • Range and overflow checks are off by default; on a 64-bit CPU a 32-bit overflow is caught by {$R+}, not by {$Q+} alone, so switch on both.
  • Delphi and Free Pascal both compile Object Pascal, Lazarus is an IDE built on Free Pascal, and the run-time library’s licence leaves your program’s licence to you.

Terms in this lesson

compiler directive
An instruction to the compiler written in the source, in braces that start with a dollar sign, such as {$mode objfpc} or {$R+}. It applies from the point where it appears, and it replaces the same setting given in fpc.cfg or on the command line.
compiler mode
The dialect a Free Pascal file is compiled in, chosen with {$mode …} in the file or -M on the command line: fpc (the default), objfpc, delphi, delphiunicode, tp and others. The mode decides, among other things, whether class is a keyword and how big an Integer is.
overflow checking
Code the compiler adds, with {$Q+} or -Co, that stops a program when integer arithmetic overflows. On a 64-bit CPU Free Pascal computes 32-bit expressions in 64 bits, so a 32-bit overflow is caught by range checking instead.
range checking
Code the compiler adds, with {$R+} or -Cr, that stops a program when a value leaves its declared range, such as 101 stored in a 0..100 subrange or an array index past the end. Free Pascal leaves it off unless you switch it on.
ShortString
Pascal's original string type: at most 255 characters, kept with a length byte in a fixed block of 256 bytes. In Free Pascal the word string means ShortString unless {$H+} is in force.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.