Object Pascalのアプリケーション(以降「アプリ」と呼びます)は、プログラム(program)とユニット(unit)で構成されます。
ここでは実行ファイル(EXE)をプログラムではなくアプリと呼ぶことにします。
標準Pascalでは、プログラムの実行文部(begin〜end)が先頭行から実行されます。宣言部の手続きや関数は実行文部から呼び出されてはじめて実行されます。
Object Pascalでは、ユニットを使用することによりプログラムの実行文部の前や後に実行される部分があります。この順序はプログラマがプログラムコードで制御するのではなく自動的に実行されます。
この順序にはルールがあるので、プログラマはこのルールを意識してアプリを構成します。
ユニットにはシステムで用意されているユニットとプログラマが作成する自作のユニットがありますが、ここでは自作のユニットについて説明します。
実行コードについても自作のプログラムコードの範囲で説明します。システムで用意されているユニットに関する実行順序については除外します。
※ コンパイル環境については、以下を参照してください。
プログラム(program)だけのアプリの例です。コードページUTF-8で作成してください。
(*****************************************************************************)
(* プログラム - AppDemo1 *)
(*****************************************************************************)
program AppDemo1;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
uses
SysUtils;
{$R *.rc}
(*****************************************************************************)
(* プログラムブロック - 宣言部 *)
(*****************************************************************************)
function ProgName: String;
begin
Result := 'AppDemo1';
end;
(*****************************************************************************)
(* プログラムブロック - 実行文部 *)
(*****************************************************************************)
begin
SetMultiByteConversionCodePage(CP_UTF8);
SetMultiByteRTLFileSystemCodePage(CP_UTF8);
WriteLn('Main : メインプログラム 開始');
WriteLn('Main : ProgName -> ', ProgName);
WriteLn('Main : メインプログラム 終了');
end.
C:\PG\FreePascal\AppDemo1>fpc64 AppDemo1.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling AppDemo1.pas
Linking AppDemo1.exe 39 lines compiled, 0.1 sec, 72976 bytes code, 5252 bytes data
Main : メインプログラム 開始
Main : ProgName -> AppDemo1
Main : メインプログラム 終了
実行文部が順に実行されて終了します。
プログラム(program)とユニット(unit)を1つ使用したアプリの例です。コードページUTF-8で作成してください。
(*****************************************************************************)
(* プログラム - AppDemo2 *)
(*****************************************************************************)
program AppDemo2;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
uses
SysUtils, Unit0;
{$R *.rc}
(*****************************************************************************)
(* プログラムブロック - 宣言部 *)
(*****************************************************************************)
function ProgName: String;
begin
Result := 'AppDemo2';
end;
(*****************************************************************************)
(* プログラムブロック - 実行文部 *)
(*****************************************************************************)
begin
WriteLn('Main : メインプログラム 開始');
WriteLn('Main : ProgName -> ', ProgName);
WriteLn('Main : UnitName -> ', UnitName);
WriteLn('Main : メインプログラム 終了');
end.
uses句に「Unit0」を追加しました。
メインプログラムでユニットで定義された「UnitName」を呼び出しています。ユニットのネームスペースは指定しません。
(*****************************************************************************)
(* ユニット - Unit0 *)
(*****************************************************************************)
unit Unit0;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'Unit0';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
SetMultiByteConversionCodePage(CP_UTF8);
SetMultiByteRTLFileSystemCodePage(CP_UTF8);
WriteLn('Unit0: 初期化処理 開始');
WriteLn('Unit0: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('Unit0: 終了処理 開始');
WriteLn('Unit0: 終了処理 終了');
end.
「SetMultiByteConversionCodePage(CP_UTF8)」と「SetMultiByteRTLFileSystemCodePage(CP_UTF8)」は「AppDemo2.pas」の実行文部には入れず「Unit0.pas」の初期化部の先頭に移動します。
C:\PG\FreePascal\AppDemo2>fpc64 AppDemo2.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling AppDemo2.pas
Compiling Unit0.pas
Linking AppDemo2.exe
89 lines compiled, 0.1 sec, 73344 bytes code, 5268 bytes data
利用するユニットも一緒にコンパイル・リンクされ実行ファイル(EXE)ができます。
Unit0: 初期化処理 開始
Unit0: 初期化処理 終了
Main : メインプログラム 開始
Main : ProgName -> AppDemo2
Main : UnitName -> Unit0
Main : メインプログラム 終了
Unit0: 終了処理 開始
Unit0: 終了処理 終了
メインプログラムの実行文部の実行前後にユニット(Unit0)の初期化部と終了処理部が実行されます。
uses句で指定したユニットを使用する前に初期化が済んでいる必要があるため自動的に初期化部が実行されます。また最後に終了処理部も自動的に実行されます。
つまり、アプリで最初に実行されるのはメインプログラムの実行文部ではなく利用するユニットの初期化部となるわけです。
「SetMultiByteConversionCodePage(CP_UTF8)」と「SetMultiByteRTLFileSystemCodePage(CP_UTF8)」はアプリの最初に実行させたいためにメインプログラムの実行文部からユニットの初期化部に移動します。
プログラム(program)とユニット(unit)を複数使用したアプリの例(その1)です。コードページUTF-8で作成してください。
(*****************************************************************************)
(* プログラム - AppDemo3 *)
(*****************************************************************************)
program AppDemo3;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
uses
SysUtils, Unit0, UnitA, UnitB, UnitC, UnitD, UnitE;
{$R *.rc}
(*****************************************************************************)
(* プログラムブロック - 宣言部 *)
(*****************************************************************************)
function ProgName: String;
begin
Result := 'AppDemo3';
end;
(*****************************************************************************)
(* プログラムブロック - 実行文部 *)
(*****************************************************************************)
begin
WriteLn('Main : メインプログラム 開始');
WriteLn('Main : ProgName -> ', ProgName);
WriteLn('Main : UnitName -> ', UnitName);
WriteLn('Main : メインプログラム 終了');
end.
uses句に「Unit0」に加え「UnitA」「UnitB」「UnitC」「UnitD」「UnitE」を追加しました。
メインプログラムでユニットで定義された「UnitName」を呼び出しています。ユニットのネームスペースは指定しません。
「Unit0」は「AppDemo2」のものと同じです。
(*****************************************************************************)
(* ユニット - Unit0 *)
(*****************************************************************************)
unit Unit0;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'Unit0';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
SetMultiByteConversionCodePage(CP_UTF8);
SetMultiByteRTLFileSystemCodePage(CP_UTF8);
WriteLn('Unit0: 初期化処理 開始');
WriteLn('Unit0: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('Unit0: 終了処理 開始');
WriteLn('Unit0: 終了処理 終了');
end.
「UnitA」〜「UnitE」はユニット名が違うだけで構造は同じです。それぞれuses句で他の自作ユニットの指定はありません。
(*****************************************************************************)
(* ユニット - UnitA *)
(*****************************************************************************)
unit UnitA;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitA';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitA: 初期化処理 開始');
WriteLn('UnitA: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitA: 終了処理 開始');
WriteLn('UnitA: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitB *)
(*****************************************************************************)
unit UnitB;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitB';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitB: 初期化処理 開始');
WriteLn('UnitB: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitB: 終了処理 開始');
WriteLn('UnitB: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitC *)
(*****************************************************************************)
unit UnitC;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitC';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitC: 初期化処理 開始');
WriteLn('UnitC: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitC: 終了処理 開始');
WriteLn('UnitC: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitD *)
(*****************************************************************************)
unit UnitD;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitD';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitD: 初期化処理 開始');
WriteLn('UnitD: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitD: 終了処理 開始');
WriteLn('UnitD: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitE *)
(*****************************************************************************)
unit UnitE;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitE';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitE: 初期化処理 開始');
WriteLn('UnitE: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitE: 終了処理 開始');
WriteLn('UnitE: 終了処理 終了');
end.
C:\PG\FreePascal\AppDemo1>fpc64 AppDemo3.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling AppDemo3.pas
Compiling Unit0.pas
Compiling UnitA.pas
Compiling UnitB.pas
Compiling UnitC.pas
Compiling UnitD.pas
Compiling UnitE.pas
Linking AppDemo3.exe
334 lines compiled, 0.1 sec, 74624 bytes code, 5348 bytes data
利用するユニットも一緒にコンパイル・リンクされ実行ファイル(EXE)ができます。
Unit0: 初期化処理 開始
Unit0: 初期化処理 終了
UnitA: 初期化処理 開始
UnitA: 初期化処理 終了
UnitB: 初期化処理 開始
UnitB: 初期化処理 終了
UnitC: 初期化処理 開始
UnitC: 初期化処理 終了
UnitD: 初期化処理 開始
UnitD: 初期化処理 終了
UnitE: 初期化処理 開始
UnitE: 初期化処理 終了
Main : メインプログラム 開始
Main : ProgName -> AppDemo3
Main : UnitName -> UnitE
Main : メインプログラム 終了
UnitE: 終了処理 開始
UnitE: 終了処理 終了
UnitD: 終了処理 開始
UnitD: 終了処理 終了
UnitC: 終了処理 開始
UnitC: 終了処理 終了
UnitB: 終了処理 開始
UnitB: 終了処理 終了
UnitA: 終了処理 開始
UnitA: 終了処理 終了
Unit0: 終了処理 開始
Unit0: 終了処理 終了
メインプログラムで複数のユニットをuses句に指定した場合、それらがさらに他の自作ユニットをuses句で指定していない場合は、メインプログラムのuses句で指定した順序で各ユニットの初期化部が実行されます。終了処理は初期化処理と逆の順序で実行されます。
「UnitA」〜「UnitE」で定義した「UnitName」関数は、ネームスペースが指定されていない場合、uses句のユニットで最後に「UnitName」関数を定義したユニットのものが選択されます。この場合は、「UnitE.UnitName」となります。
プログラム(program)とユニット(unit)を複数使用したアプリの例(その2)です。コードページUTF-8で作成してください。
(*****************************************************************************)
(* プログラム - AppDemo4 *)
(*****************************************************************************)
program AppDemo4;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
uses
SysUtils, Unit0, UnitA, UnitB, UnitC, UnitD, UnitE;
{$R *.rc}
(*****************************************************************************)
(* プログラムブロック - 宣言部 *)
(*****************************************************************************)
function ProgName: String;
begin
Result := 'AppDemo4';
end;
(*****************************************************************************)
(* プログラムブロック - 実行文部 *)
(*****************************************************************************)
begin
WriteLn('Main : メインプログラム 開始');
WriteLn('Main : ProgName -> ', ProgName);
WriteLn('Main : UnitName -> ', UnitName);
WriteLn('Main : メインプログラム 終了');
end.
uses句は「AppDemo3」と同じく「Unit0」「UnitA」「UnitB」「UnitC」「UnitD」「UnitE」を指定しています。さらにメインプログラムでは参照しませんが「UnitF」を用意します。
メインプログラムでユニットで定義された「UnitName」を呼び出しています。ユニットのネームスペースは指定しません。
「Unit0」は「AppDemo2」「AppDemo3」のものと同じです。
(*****************************************************************************)
(* ユニット - Unit0 *)
(*****************************************************************************)
unit Unit0;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'Unit0';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
SetMultiByteConversionCodePage(CP_UTF8);
SetMultiByteRTLFileSystemCodePage(CP_UTF8);
WriteLn('Unit0: 初期化処理 開始');
WriteLn('Unit0: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('Unit0: 終了処理 開始');
WriteLn('Unit0: 終了処理 終了');
end.
「UnitA」「UnitB」「UnitC」「UnitD」は「AppDemo3」に対してuses句の指定に変化を加えています。他の自作ユニットの指定を追加しました。
(*****************************************************************************)
(* ユニット - UnitA *)
(*****************************************************************************)
unit UnitA;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils, UnitE;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitA';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitA: 初期化処理 開始');
WriteLn('UnitA: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitA: 終了処理 開始');
WriteLn('UnitA: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitB *)
(*****************************************************************************)
unit UnitB;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils, UnitE, UnitD;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitB';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitB: 初期化処理 開始');
WriteLn('UnitB: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitB: 終了処理 開始');
WriteLn('UnitB: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitC *)
(*****************************************************************************)
unit UnitC;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils, UnitF;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitC';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitC: 初期化処理 開始');
WriteLn('UnitC: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitC: 終了処理 開始');
WriteLn('UnitC: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitD *)
(*****************************************************************************)
unit UnitD;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils, UnitC;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitD';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitD: 初期化処理 開始');
WriteLn('UnitD: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitD: 終了処理 開始');
WriteLn('UnitD: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitE *)
(*****************************************************************************)
unit UnitE;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitE';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitE: 初期化処理 開始');
WriteLn('UnitE: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitE: 終了処理 開始');
WriteLn('UnitE: 終了処理 終了');
end.
(*****************************************************************************)
(* ユニット - UnitF *)
(*****************************************************************************)
unit UnitF;
{$MODE OBJFPC}{$H+}{$J-}
{$MINFPCONSTPREC 64}
{$CODEPAGE UTF8}
(*****************************************************************************)
(* インターフェース部 *)
(*****************************************************************************)
interface
uses
SysUtils;
function UnitName: String;
(*****************************************************************************)
(* 実現部 *)
(*****************************************************************************)
implementation
function UnitName: String;
begin
Result := 'UnitF';
end;
(*****************************************************************************)
(* 初期化部 *)
(*****************************************************************************)
initialization
WriteLn('UnitF: 初期化処理 開始');
WriteLn('UnitF: 初期化処理 終了');
(*****************************************************************************)
(* 終了処理部 *)
(*****************************************************************************)
finalization
WriteLn('UnitF: 終了処理 開始');
WriteLn('UnitF: 終了処理 終了');
end.
メインプログラムからのuses句から各ユニットのuses句の参照関係は以下のようになります。追加した「UnitF」はメインプログラムからは直接参照されませんが、「UnitC」から参照されます。
メインプログラムは自分のuses句の指定順「Unit0」「UnitA」「UnitB」「UnitC」「UnitD」「UnitE」で初期化する順を決めます。メインプログラムでは「UnitF」を参照していません。各ユニットも同じように自分のuses句の指定順に初期化の順序を決めます。もう参照するユニットがなくなったらそのユニットが初期化対象となります。そしてひとつ前に戻って初期化対象とします。既に初期化されている場合はスキップします。
最初に「Unit0」を初期化対象とします。「Unit0」は他の参照がないため初期化対象@で確定します。
次に「UnitA」を初期化対象とします。さらに「UnitE」を参照しているので「UnitE」を初期化対象とします。「UnitE」は他の参照がないため初期化対象Aで確定します。ひとつ戻って「UnitA」を初期化対象Bで確定します。
次に「UnitB」を初期化対象とします。さらに「UnitE」を参照しているので「UnitE」を初期化対象とします。「UnitE」は初期化対象Aで確定しているのでスキップします。次に「UnitD」がuses句で指定されているので「UnitD」を初期化対象とします。さらに「UnitC」を参照しているので「UnitC」を初期化対象とします。さらに「UnitF」を参照しているので「UnitF」を初期化対象とします。「UnitF」は他の参照がないため初期化対象Cで確定します。ひとつ戻って「UnitC」を初期化対象Dで確定します。ひとつ戻って「UnitD」を初期化対象Eで確定します。ひとつ戻って「UnitB」を初期化対象Fで確定します。
「Unit0」「UnitA」「UnitB」をたどると「Unit0」「UnitA」〜「UnitE」そして追加の「UnitF」の初期化順序@〜Eが確定することになります。
C:\PG\FreePascal\AppDemo1>fpc64 AppDemo4.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling AppDemo4.pas
Compiling Unit0.pas
Compiling UnitA.pas
Compiling UnitE.pas
Compiling UnitB.pas
Compiling UnitD.pas
Compiling UnitC.pas
Compiling UnitF.pas
Linking AppDemo4.exe
383 lines compiled, 0.1 sec, 74880 bytes code, 5364 bytes data
利用するユニットも一緒にコンパイル・リンクされ実行ファイル(EXE)ができます。メインプログラムからは間接的に参照される「UnitF」もコンパイル・リンクされます。
ユニットのコンパイル順序は、初期化順序ではなく、単純に5.1の参照関係の図をたどって見つかった順になっています。コンパイル順序自体はどうでもよいので、もれなく必要なユニットを見つけるためですね。これは現在のコンパイラの仕様であり今後もそうである保証はありません。
Unit0: 初期化処理 開始
Unit0: 初期化処理 終了
UnitE: 初期化処理 開始
UnitE: 初期化処理 終了
UnitA: 初期化処理 開始
UnitA: 初期化処理 終了
UnitF: 初期化処理 開始
UnitF: 初期化処理 終了
UnitC: 初期化処理 開始
UnitC: 初期化処理 終了
UnitD: 初期化処理 開始
UnitD: 初期化処理 終了
UnitB: 初期化処理 開始
UnitB: 初期化処理 終了
Main : メインプログラム 開始
Main : ProgName -> AppDemo4
Main : UnitName -> UnitE
Main : メインプログラム 終了
UnitB: 終了処理 開始
UnitB: 終了処理 終了
UnitD: 終了処理 開始
UnitD: 終了処理 終了
UnitC: 終了処理 開始
UnitC: 終了処理 終了
UnitF: 終了処理 開始
UnitF: 終了処理 終了
UnitA: 終了処理 開始
UnitA: 終了処理 終了
UnitE: 終了処理 開始
UnitE: 終了処理 終了
Unit0: 終了処理 開始
Unit0: 終了処理 終了
「5.1 ユニットの参照関係と初期化順序の確定」で確定した順序で各ユニットの初期化部が実行されます。終了処理は初期化処理と逆の順序で実行されます。
「UnitA」〜「UnitE」で定義した「UnitName」関数は、ネームスペースが指定されていない場合、uses句のユニットで最後に「UnitName」関数を定義したユニットのものが選択されます。この場合は、「UnitE.UnitName」となります。初期化処理の順序は関係ありません。ネームスペースを指定すればすべてのユニットの「UnitName」を使用することができます。「UnitA.UnitName」「UnitB.UnitName」など。
必須ではありませんが、「Unit0」のように、アプリで使用する自作ユニットで最初に初期化される特別扱いのユニットを用意し、それをアプリの初期化のためのユニットにするとよいと思います。uses句の後続のユニットが「Unit0」を参照しても初期化順序は変わらず、それら全体に共通のインターフェース(データや関数・手続きなど)を提供することもできます。ただし、「Unit0」がuses句で他の自作ユニットを参照しないようにします。他のユニットを参照すると、そのユニットの初期化処理が先になってしまうためです。
ここでは「Unit0」という名前ですが、実際には何かセンスの良い名前をつけてください。
本記事のプログラムコードなどは以下のページでダウンロードできます。