Delphi と Free Pascal(FPC)
『Pascal』の商用ラインを代表する Delphi と、オープンソースラインを代表する Free Pascal(FPC) は、どちらも Turbo Pascal の遺産を継承しながら独自の方向へと発展してきました。Delphi は Borland(現 Embarcadero)が Windows 向け RAD ツールとして商業的に発展させ、Free Pascal はコミュニティ主導でマルチプラットフォーム・オープンソースの方向へと進化しました。このページでは両者の特徴・相違点・共通点を整理します。
Delphi の概要
| 項目 | 内容 |
|---|---|
| 開発元 | Borland → CodeGear → Embarcadero Technologies と引き継がれています。現在は Embarcadero 社が開発・販売しています。 |
| 初版リリース | 1995年。Turbo Pascal の後継として Windows 向け RAD(Rapid Application Development)ツールを目指してリリースされました。 |
| 言語 | Object Pascal(Delphi 方言)を採用しています。クラス・インターフェース・ジェネリクス・匿名メソッドなど現代的な機能を順次追加してきました。 |
| GUI フレームワーク | VCL(Visual Component Library)を Windows 向けに、FMX(FireMonkey)を Windows・macOS・iOS・Android 向けのクロスプラットフォームフレームワークとして提供しています。 |
| 対応プラットフォーム | Windows・macOS・iOS・Android・Linux(サーバー用途限定)に対応しています。 |
| ライセンス | 商用ライセンスです。Community Edition として個人・学習・オープンソース開発向けに無償版も提供されています。 |
| 主な用途 | エンタープライズ向け Windows アプリケーション・業務システム・データベースフロントエンドの開発で多く使われています。 |
Free Pascal(FPC)の概要
| 項目 | 内容 |
|---|---|
| 開発元 | Florian Klämpfl を中心とするオープンソースコミュニティが開発しています。 |
| 初版リリース | 1993年ごろに開発が始まり、1996年に公開されました。Turbo Pascal 7.0 および Delphi との高い互換性を目標としています。 |
| 言語 | Turbo Pascal モード・Delphi モード・Free Pascal 独自モードなど複数のコンパイルモードを持ちます。スイッチ {$mode delphi} などで切り替えられます。 |
| GUI フレームワーク | 単体では GUI を持たず、Lazarus IDE と組み合わせることで LCL(Lazarus Component Library)を使ったクロスプラットフォーム GUI 開発が可能になります。 |
| 対応プラットフォーム | Windows・macOS・Linux・FreeBSD・Raspberry Pi(ARM)・Nintendo Switch など非常に多くのプラットフォームに対応しています。 |
| ライセンス | GPL(コンパイラ本体)および LGPL with linking exception(ランタイムライブラリ)です。商用ソフトウェアにも組み込んで利用できます。 |
| 主な用途 | クロスプラットフォームのコマンドラインツール・組み込みシステム・Lazarus を使ったデスクトップアプリケーション・プログラミング教育に使われています。 |
Delphi と Free Pascal の比較
| 比較項目 | Delphi | Free Pascal(FPC) |
|---|---|---|
| ライセンス | 商用(Community Edition あり)です。 | オープンソース(GPL/LGPL)です。 |
| 言語仕様の拡張 | Embarcadero が主導して追加・決定します。 | コミュニティが合意して追加・決定します。 |
| Delphi 互換性 | Delphi 自身が基準です。 | {$mode delphi} で高い互換性を持ちます。 |
| IDE | RAD Studio(統合 IDE(Integrated Development Environment、統合開発環境))が付属します。 | Lazarus IDE を別途インストールして使います。 |
| 対応 CPU アーキテクチャ | x86・x86_64・ARM・ARM64 などに対応します。 | x86・x86_64・ARM・MIPS・RISC-V など非常に多くに対応します。 |
| コミュニティ規模 | 商用サポートと有償ドキュメントが充実しています。 | フォーラム・Wiki・GitHub などで無償のリソースが豊富です。 |
| ランタイムライブラリ | RTL(Run-Time Library、ランタイムライブラリ)・VCL・FMX などが提供されます。 | RTL・FCL(Free Component Library、フリーコンポーネントライブラリ)が提供されます。 |
コンパイルモードの切り替え(Free Pascal)
| モード指定 | 概要 |
|---|---|
{$mode fpc} | Free Pascal 独自の既定モードです。Turbo Pascal より厳格な型チェックが行われます。 |
{$mode tp} | Turbo Pascal 7.0 互換モードです。古いソースコードを再利用する際に使います。 |
{$mode delphi} | Delphi 互換モードです。Delphi で書かれたソースを Free Pascal でコンパイルする際に使います。 |
{$mode objfpc} | Free Pascal 独自のオブジェクト指向拡張モードです。Delphi との互換性を保ちつつ FPC 独自機能を追加しています。 |
サンプルコード
jujutsu_delphi_fpc.pas
{ jujutsu_delphi_fpc.pas — Delphi / Free Pascal の機能比較サンプルです }
{ 呪術廻戦のキャラクターデータを使って }
{ クラス・インターフェース・例外処理など }
{ Delphi と Free Pascal の両方で動作する Object Pascal の書き方を確認します }
{
コンパイルと実行:
fpc jujutsu_delphi_fpc.pas && ./jujutsu_delphi_fpc
}
{$mode delphi} { Free Pascal で Delphi 互換モードを有効にします }
program jujutsu_delphi_fpc;
uses
SysUtils; { IntToStr・FloatToStrF などを使います }
{ ============================================================
インターフェース宣言
Delphi・Free Pascal(objfpc/delphi モード)両方でサポートされます
============================================================ }
type
ISorcerer = interface
['{A1B2C3D4-0000-0000-0000-000000000001}'] { GUID(Globally Unique Identifier、グローバル一意識別子)— Delphi 互換 }
function GetName : string;
function GetGrade : integer;
procedure ShowInfo;
end;
{ ============================================================
基底クラス TSorcerer
============================================================ }
TSorcerer = class(TInterfacedObject, ISorcerer)
private
FName : string; { 術師の名前 }
FGrade : integer; { 等級(1 が最上位) }
public
constructor Create(const AName : string; const AGrade : integer);
function GetName : string; virtual;
function GetGrade : integer; virtual;
procedure ShowInfo; virtual;
end;
{ ============================================================
派生クラス TSpecialGradeSorcerer(特級呪術師)
============================================================ }
TSpecialGradeSorcerer = class(TSorcerer)
private
FDomain : string; { 領域展開の名称 }
public
constructor Create(const AName : string; const ADomain : string);
procedure ShowInfo; override; { ShowInfo をオーバーライドします }
end;
{ ============================================================
TSorcerer の実装
============================================================ }
constructor TSorcerer.Create(const AName : string; const AGrade : integer);
begin
inherited Create;
FName := AName;
FGrade := AGrade;
end;
function TSorcerer.GetName : string;
begin
Result := FName;
end;
function TSorcerer.GetGrade : integer;
begin
Result := FGrade;
end;
procedure TSorcerer.ShowInfo;
begin
WriteLn(' 名前: ', FName, ' 等級: ', IntToStr(FGrade), '級');
end;
{ ============================================================
TSpecialGradeSorcerer の実装
============================================================ }
constructor TSpecialGradeSorcerer.Create(const AName : string; const ADomain : string);
begin
inherited Create(AName, 0); { 等級 0 = 特級 }
FDomain := ADomain;
end;
procedure TSpecialGradeSorcerer.ShowInfo;
begin
WriteLn(' 名前: ', GetName, ' 等級: 特級 領域展開: ', FDomain);
end;
{ ============================================================
メインプログラム
============================================================ }
var
{ 呪術廻戦キャラクターのオブジェクト配列 }
sorcerers : array[1..5] of TSorcerer;
i : integer;
begin
{ -----------------------------------------------
呪術師オブジェクトの生成
特級呪術師は TSpecialGradeSorcerer で生成します
----------------------------------------------- }
sorcerers[1] := TSpecialGradeSorcerer.Create('五条悟', '無量空処');
sorcerers[2] := TSpecialGradeSorcerer.Create('夏油傑', '偽夏油の術式');
sorcerers[3] := TSorcerer.Create('虎杖悠仁', 1);
sorcerers[4] := TSorcerer.Create('伏黒恵', 2);
sorcerers[5] := TSorcerer.Create('釘崎野薔薇', 3);
{ -----------------------------------------------
全術師の情報を表示します
----------------------------------------------- }
WriteLn('===== 呪術師名簿 =====');
for i := 1 to 5 do begin
sorcerers[i].ShowInfo;
end;
WriteLn('');
{ -----------------------------------------------
例外処理のサンプル
Free Pascal・Delphi 両方で同じ構文を使えます
----------------------------------------------- }
WriteLn('===== 等級チェック(例外処理) =====');
try
{ 等級が範囲外の場合に例外を発生させます }
if sorcerers[1].GetGrade <= 0 then
raise ERangeError.Create('特級は等級 0 以下です(特別扱いが必要)。');
except
on E : ERangeError do
WriteLn(' [キャッチ] ERangeError: ', E.Message);
on E : Exception do
WriteLn(' [キャッチ] Exception: ', E.Message);
end;
WriteLn('');
{ -----------------------------------------------
インターフェース経由でのアクセス
ISorcerer インターフェース変数に代入します
----------------------------------------------- }
WriteLn('===== インターフェース経由で名前を取得 =====');
for i := 1 to 5 do begin
WriteLn(' ISorcerer.GetName -> ', (sorcerers[i] as ISorcerer).GetName);
end;
WriteLn('');
WriteLn('処理が完了しました。');
end.
fpc jujutsu_delphi_fpc.pas && ./jujutsu_delphi_fpc Free Pascal Compiler version 3.2.2 ... Linking ./jujutsu_delphi_fpc ===== 呪術師名簿 ===== 名前: 五条悟 等級: 特級 領域展開: 無量空処 名前: 夏油傑 等級: 特級 領域展開: 偽夏油の術式 名前: 虎杖悠仁 等級: 1級 名前: 伏黒恵 等級: 2級 名前: 釘崎野薔薇 等級: 3級 ===== 等級チェック(例外処理) ===== [キャッチ] ERangeError: 特級は等級 0 以下です(特別扱いが必要)。 ===== インターフェース経由で名前を取得 ===== ISorcerer.GetName -> 五条悟 ISorcerer.GetName -> 夏油傑 ISorcerer.GetName -> 虎杖悠仁 ISorcerer.GetName -> 伏黒恵 ISorcerer.GetName -> 釘崎野薔薇 処理が完了しました。
jujutsu_ifdef.pas
{$mode delphi}
program jujutsu_ifdef;
uses
SysUtils;
var
platform_name : string;
char_name : string;
begin
char_name := '五条悟';
{ {$IFDEF} による条件コンパイル: プラットフォームで処理を分岐します }
{$IFDEF WINDOWS}
platform_name := 'Windows';
{$ELSE}
{$IFDEF LINUX}
platform_name := 'Linux';
{$ELSE}
platform_name := '不明なプラットフォーム';
{$ENDIF}
{$ENDIF}
WriteLn(char_name, ' が ', platform_name, ' 上で起動しました。');
WriteLn('Free Pascal / Delphi どちらでもコンパイル可能です。');
end.
fpc jujutsu_ifdef.pas && ./jujutsu_ifdef Free Pascal Compiler version ... Linking ./jujutsu_ifdef 五条悟 が Linux 上で起動しました。 Free Pascal / Delphi どちらでもコンパイル可能です。
jujutsu_unit_diff.pas
{$mode delphi}
program jujutsu_unit_diff;
uses
SysUtils,
{$IFDEF WINDOWS}
Windows { Windows API を使う場合は Windows ユニットを uses します }
{$ELSE}
BaseUnix { Linux/macOS では BaseUnix ユニットを uses します }
{$ENDIF}
;
var
char_name : string;
pid : LongInt;
begin
char_name := '虎杖悠仁';
{ プロセス ID の取得方法もプラットフォームで異なります }
{$IFDEF WINDOWS}
pid := GetCurrentProcessId;
{$ELSE}
pid := fpGetPid;
{$ENDIF}
WriteLn(char_name, ' のプロセス ID: ', pid);
WriteLn('ユニット名はプラットフォームごとに異なります。');
end.
fpc jujutsu_unit_diff.pas && ./jujutsu_unit_diff Free Pascal Compiler version ... Linking ./jujutsu_unit_diff 虎杖悠仁 のプロセス ID: 12345 ユニット名はプラットフォームごとに異なります。
よくあるミス
Delphi専用構文をFPCで{$mode delphi}なしで使用する
FPC のデフォルトモードは ObjFPC で、Delphi とは構文が異なる部分があります。Delphi の構文をそのまま使うには {$mode delphi} をファイル先頭に付けます。付けないと「identifier not found」や型不一致のコンパイルエラーが出ることがあります。
{ Delphi 構文を FPC で使う場合は先頭に記述します }
{$mode delphi}
program sample;
uses
SysUtils;
begin
WriteLn('Delphi 互換モードで動作しています。');
end.
インターフェースのGUIDを書き忘れる
Delphi のインターフェースには GUID(['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'])が必要なケースがあります。GUID なしだと QueryInterface が正しく機能せず、インターフェース型キャスト(as 演算子)が実行時エラーになります。
type
{ GUID なし: QueryInterface が機能しません }
INoGuid = interface
procedure DoSomething;
end;
{ GUID あり: as 演算子でのキャストが機能します }
IWithGuid = interface
['{A1B2C3D4-1234-5678-ABCD-000000000001}']
procedure DoSomething;
end;
概要
Delphi は商用の完成度の高い IDE・フレームワーク・サポートを求める場合に、Free Pascal(FPC) はオープンソース・クロスプラットフォーム・コスト無しで始めたい場合に適しています。両者は Object Pascal という共通の言語基盤を持っており、{$mode delphi} ディレクティブを使うことで Free Pascal 上でも多くの Delphi コードをそのままコンパイルできます。クラス・インターフェース・例外処理など Object Pascal の機能については クラスの基本・インターフェース型・例外処理 も合わせて参照してください。Free Pascal のセットアップ方法は Free Pascal のセットアップ を確認してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。