Units & Program Organization

21.1 Unit structure

Using it (main.pas, in the same folder):

unit Geometry;

{$mode objfpc}{$H+}

interface                           // public part: what other units see

type
  TPoint2D = record
    X, Y: Double;
  end;

function Distance(const A, B: TPoint2D): Double;
function CallCount: Integer;

implementation                      // private part: bodies and hidden helpers

uses
  Math;                             // used only by the implementation

var
  FCalls: Integer;                  // unit-private global

function Distance(const A, B: TPoint2D): Double;
begin
  Inc(FCalls);
  Result := Hypot(A.X - B.X, A.Y - B.Y);
end;

function CallCount: Integer;
begin
  Result := FCalls;
end;

initialization                      // runs once at program start (in dependency order)
  FCalls := 0;

finalization                        // runs once at program exit (reverse order)
  // release unit-level resources here

end.
program Main;
{$mode objfpc}{$H+}
uses
  Geometry;
var
  A, B: TPoint2D;
begin
  A.X := 0; A.Y := 0;
  B.X := 3; B.Y := 4;
  Writeln(Distance(A, B):0:1);    // 5.0
  Writeln(CallCount);             // 1
end.

21.2 Sections

must match the file name (geometry.pas; FPC on Linux prefers lowercase file names) public types, constants, variables, routine headings, class declarations routine and method bodies, private declarations uses (interface) units whose declarations the interface needs uses (implementation) units needed only by the implementation — prefer this; it also resolves circular references startup code (alternative: begin... end. at the end of the unit) cleanup code, runs only if initialization ran

21.3 Circular references

Two units cannot use each other in their interface sections. Solutions:

Move one uses to the implementation section.

Extract shared types into a third unit.

Use interfaces or abstract base classes to decouple.

21.4 Unit scope names and namespaces

Delphi organizes RTL/VCL units into dotted namespaces: System.SysUtils, System.Classes, Vcl.Forms, FMX.Forms, Data.DB. A project setting ("Unit scope names") lets you write SysUtils instead of System.SysUtils. FPC 3.2 uses the short names (SysUtils, Classes); recent FPC versions add dotted aliases. For code shared between both compilers, use the short names and add the unit scope names in Delphi.

21.5 Include files

Include files are used for shared compiler directives, platform-specific code fragments, and generated code. Prefer units for anything that declares types or routines.

{$I settings.inc}          // textual inclusion (same as {$INCLUDE settings.inc})

21.6 Compilation model

FPC compiles each unit to a .ppu (interface information) and .o (object code); Delphi produces .dcu files.

The compiler recompiles a unit only if its source or the interface of a unit it depends on changed — which is why Pascal builds are very fast.

Libraries: FPC library projects produce .dll/.so/.dylib; Delphi library and packages (.bpl) for design-time components and run-time modules.

21.7 A shared library

library MathLib;
{$mode objfpc}{$H+}

function AddInts(A, B: Integer): Integer; cdecl;
begin
  Result := A + B;
end;

exports
  AddInts;

end.