Pascal 日和 ホームページ



更新:2026-01-03



備忘録インデックス

Object Pascal 備忘録  (Free Pascal OBJFPCモード)



アプリ(EXE)内の実行順序


〜 Object Pascal(Free Pascal)のアプリ(EXE)内の初期化処理と終了処理の実行タイミングについて 〜




1. はじめに


Object Pascalのアプリケーション(以降「アプリ」と呼びます)は、プログラム(program)とユニット(unit)で構成されます。

ここでは実行ファイル(EXE)をプログラムではなくアプリと呼ぶことにします。

標準Pascalでは、プログラムの実行文部(begin〜end)が先頭行から実行されます。宣言部の手続きや関数は実行文部から呼び出されてはじめて実行されます。

Object Pascalでは、ユニットを使用することによりプログラムの実行文部の前や後に実行される部分があります。この順序はプログラマがプログラムコードで制御するのではなく自動的に実行されます。

この順序にはルールがあるので、プログラマはこのルールを意識してアプリを構成します。

ユニットにはシステムで用意されているユニットとプログラマが作成する自作のユニットがありますが、ここでは自作のユニットについて説明します。

実行コードについても自作のプログラムコードの範囲で説明します。システムで用意されているユニットに関する実行順序については除外します。

※ コンパイル環境については、以下を参照してください。

 ⇒ Free Pascal コンパイル環境




2. プログラムだけで自作のユニットを使用しない場合


プログラム(program)だけのアプリの例です。コードページUTF-8で作成してください。


 プログラムファイル1 : AppDemo1.pas
(*****************************************************************************)
(* プログラム - 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.


2.1 アプリをコンパイルする


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


2.2 アプリを実行する


Main : メインプログラム 開始
Main : ProgName -> AppDemo1
Main : メインプログラム 終了


実行文部が順に実行されて終了します。




3. プログラムと自作のユニットを1つ使用した場合


プログラム(program)とユニット(unit)を1つ使用したアプリの例です。コードページUTF-8で作成してください。


 プログラムファイル2 : AppDemo2.pas
(*****************************************************************************)
(* プログラム - 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.pas
(*****************************************************************************)
(* ユニット - 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」の初期化部の先頭に移動します。


3.1 アプリをコンパイルする


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)ができます。


3.2 アプリを実行する


Unit0: 初期化処理 開始
Unit0: 初期化処理 終了
Main : メインプログラム 開始
Main : ProgName -> AppDemo2
Main : UnitName -> Unit0
Main : メインプログラム 終了
Unit0: 終了処理 開始
Unit0: 終了処理 終了


メインプログラムの実行文部の実行前後にユニット(Unit0)の初期化部と終了処理部が実行されます。

uses句で指定したユニットを使用する前に初期化が済んでいる必要があるため自動的に初期化部が実行されます。また最後に終了処理部も自動的に実行されます。

つまり、アプリで最初に実行されるのはメインプログラムの実行文部ではなく利用するユニットの初期化部となるわけです。

「SetMultiByteConversionCodePage(CP_UTF8)」と「SetMultiByteRTLFileSystemCodePage(CP_UTF8)」はアプリの最初に実行させたいためにメインプログラムの実行文部からユニットの初期化部に移動します。




4. プログラムと自作のユニットを複数使用した場合(その1)


プログラム(program)とユニット(unit)を複数使用したアプリの例(その1)です。コードページUTF-8で作成してください。


 プログラムファイル3 : AppDemo3.pas
(*****************************************************************************)
(* プログラム - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.


4.1 アプリをコンパイルする


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)ができます。


4.2 アプリを実行する


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」となります。




5. プログラムと自作のユニットを複数使用した場合(その2)


プログラム(program)とユニット(unit)を複数使用したアプリの例(その2)です。コードページUTF-8で作成してください。


 プログラムファイル4 : AppDemo4.pas
(*****************************************************************************)
(* プログラム - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.pas
(*****************************************************************************)
(* ユニット - 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.


5.1 ユニットの参照関係と初期化順序の確定


メインプログラムからのuses句から各ユニットのuses句の参照関係は以下のようになります。追加した「UnitF」はメインプログラムからは直接参照されませんが、「UnitC」から参照されます。



メインプログラムは自分のuses句の指定順「Unit0」「UnitA」「UnitB」「UnitC」「UnitD」「UnitE」で初期化する順を決めます。メインプログラムでは「UnitF」を参照していません。各ユニットも同じように自分のuses句の指定順に初期化の順序を決めます。もう参照するユニットがなくなったらそのユニットが初期化対象となります。そしてひとつ前に戻って初期化対象とします。既に初期化されている場合はスキップします。


  1. 最初に「Unit0」を初期化対象とします。「Unit0」は他の参照がないため初期化対象@で確定します。

  2. 次に「UnitA」を初期化対象とします。さらに「UnitE」を参照しているので「UnitE」を初期化対象とします。「UnitE」は他の参照がないため初期化対象Aで確定します。ひとつ戻って「UnitA」を初期化対象Bで確定します。

  3. 次に「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が確定することになります。


5.2 アプリをコンパイルする


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の参照関係の図をたどって見つかった順になっています。コンパイル順序自体はどうでもよいので、もれなく必要なユニットを見つけるためですね。これは現在のコンパイラの仕様であり今後もそうである保証はありません。


5.3 アプリを実行する


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」など。




6. アプリの初期化ユニットを用意する


必須ではありませんが、「Unit0」のように、アプリで使用する自作ユニットで最初に初期化される特別扱いのユニットを用意し、それをアプリの初期化のためのユニットにするとよいと思います。uses句の後続のユニットが「Unit0」を参照しても初期化順序は変わらず、それら全体に共通のインターフェース(データや関数・手続きなど)を提供することもできます。ただし、「Unit0」がuses句で他の自作ユニットを参照しないようにします。他のユニットを参照すると、そのユニットの初期化処理が先になってしまうためです。

ここでは「Unit0」という名前ですが、実際には何かセンスの良い名前をつけてください。




7. ダウンロード


本記事のプログラムコードなどは以下のページでダウンロードできます。


Object Pascal 備忘録




8. 参照


Free Pascal コンパイル環境

プログラムの構成



[ライセンスについて]