Compile a Pascal Program Reliably with FPC 3.2.2
You will compile a Pascal program with the installed Free Pascal Compiler, keep generated files in a build directory, and check which configuration and target the compiler used. Allow about 15 minutes for a first build, including one small diagnostic test. The examples target the installed amd64 Linux package, fp-compiler-3.2.2, version 3.2.2+dfsg-32.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide uses the local FPC 3.2.2 manpages. The manpage is a quick reference and warns that the larger compiler manuals can contain newer detail, so treat the command output on your host as the final authority when a project depends on a particular package build.
1. Check the compiler before building
Start without changing files. The short information switches report the compiler version, operating system, processor, target operating system and target processor:
$ command -v fpc
/usr/bin/fpc
$ fpc -iV
3.2.2
$ fpc -iSO
linux
$ fpc -iSP
x86_64
$ dpkg-query -W -f='${Package} ${Version}\n' fp-compiler-3.2.2
fp-compiler-3.2.2 3.2.2+dfsg-32
On this installation, the compiler identifies itself as version 3.2.2 and targets Linux on x86_64. The package version includes a Debian or Ubuntu packaging suffix, which is useful when comparing diagnostics between machines.
Checkpoint: do not continue if command -v fpc resolves to an unexpected installation. A different compiler earlier in PATH can make a correct project appear broken.
2. Compile into a separate build directory
Give FPC your Pascal source file. The -FE option sets the executable and unit output path, -FU places compiled units in a separate directory, and -o gives a program a precise executable name. These options affect generated files, not the source.
$ mkdir -p build/units
$ fpc -FEbuild -FUbuild/units -ohello src/hello.pas
Free Pascal Compiler version 3.2.2+dfsg-32 [2024/01/05]
Target OS: Linux for x86-64
Compiling src/hello.pas
Linking build/hello
... lines compiled, ... sec
Replace src/hello.pas with your source path. The exact line count and elapsed time vary. A successful compile normally leaves the executable at build/hello and unit files under build/units. The command does not need sudo when the project is in a directory you can write.
Run the result and check its status:
$ ./build/hello
Hello from Pascal
$ printf 'exit status: %s\n' "$?"
exit status: 0
The output is determined by your program. Status 0 tells you that this invocation returned successfully; it is not a test of every code path.
3. Make warnings and useful detail visible
The installed configuration enables some defaults, so make diagnostic intent explicit when investigating a build. The -v option takes letters that can be combined. i shows general information, w warnings, n notes, h hints, and u the names of files opened by the compiler.
$ fpc -viwnh -FEbuild -FUbuild/units -ohello src/hello.pas
... compiler information, warnings, notes and hints ...
Use -vu when a unit or include file cannot be found. It can reveal the search path that your normal command hides. The -l option prints a version line at the top, while -h prints the option list and exits. Avoid starting with -va unless you need every diagnostic category: its output can obscure the first real error.
4. Understand the configuration file
FPC reads a configuration file before it processes the remaining command-line options. On Linux, the documented search includes the current directory, ~/.fpc.cfg, a directory named by PPC_CONFIG_PATH, the compiler's installation path and finally /etc. This is why the same command can behave differently in a project directory or under another account.
Inspect the active system configuration without editing it:
$ readlink -f /etc/fpc.cfg
/etc/fpc.cfg
$ sed -n '1,80p' /etc/fpc.cfg
The configuration syntax accepts compiler options, comments beginning with #, and conditional directives such as #IFDEF, #ELSE and #ENDIF. It can also define symbols with #DEFINE and include another file with #INCLUDE. Keep project-specific choices in a project file rather than modifying a package-managed file under /etc.
5. Use a project configuration deliberately
The manpage documents @FILE as a way to read a second configuration file. It is an at-sign followed by the filename, not a -@ option. For a harmless check, create a file such as project.fpc.cfg containing:
# Project-only compiler settings
-Fu./lib
#IFDEF DEBUG
-gl
#ENDIF
Then invoke the compiler with that file before the source file:
$ fpc @project.fpc.cfg -FEbuild -FUbuild/units -ohello src/hello.pas
Command-line options are still processed after the configuration file. That lets a one-off command override a project default, but it also creates a distraction trap: a setting hidden in a configuration file can be the real reason a build differs from a plain invocation. Use -vu and compare the exact command when debugging.
To test whether the system configuration is supplying required unit paths, use -n, which tells FPC not to read any configuration file:
$ fpc -n -FEbuild -FUbuild/units -ohello src/hello.pas
Fatal: Can't find unit system used by Hello
Fatal: Compilation aborted
The program name and wording can differ. A failure such as this indicates missing compiler paths, not a Pascal syntax error. Remove -n for the ordinary build, or provide a complete project configuration. Do not copy random unit paths from another host.
6. Add checks only while diagnosing
FPC can generate runtime checks including input/output, integer overflow, range and stack checks with -Ci, -Co, -Cr and -Ct. These are useful for a debug build but can change runtime behaviour and performance. Keep them in a named debug configuration and do not assume that a release build has the same checks.
For debugger work, -g adds debugging information and -gw requests DWARF information. The -O options change optimisation, so begin with checks and debugging enabled and optimisation modest, then test the release command separately. Never interpret a clean checked build as proof that untested input is safe.
Some switches change linking rather than compilation. -Cn, also available as -E, omits linking and leaves no runnable executable. -Xst requests static linking, while -Xs strips symbols according to the installed configuration. Use those deliberately and inspect the output with file build/hello or ldd build/hello where appropriate. Static linking can expose missing libraries and licensing or update assumptions; it is not a routine fix for a failed build.
7. Recover from a bad build
Compilation can leave an executable or unit files from an earlier attempt. If the source changes but the output does not, compile to a new name first and compare it:
$ fpc -FEbuild -FUbuild/units -ohello.new src/hello.pas
$ file build/hello.new
$ ./build/hello.new
Only after checking the new program should you replace the old executable. If you used a temporary output name, the recovery action is simply to leave the old file in place and remove the new one with your normal file-management command. Do not use a broad recursive deletion in a project directory just to clear compiler output. Confirm the exact paths first.
Done means
fpc -iVreports the expected 3.2.2 compiler.- The program builds without elevated privileges into a dedicated build directory.
- The executable runs and its exit status is checked.
- You know whether the build used
/etc/fpc.cfg, a project file, or-n. - Diagnostic, debug and linking switches are deliberate rather than inherited by accident.
- A failed replacement build cannot silently overwrite the last working executable.