Question

I have a project where multiple units have Initialization sections. I would like to control the order in which this blocks are executed.

According to the following question, this is based on the order in which the units were compiled, so ultimately the order should be based on the arrangement of units in the uses clause of the source DPR.

The following is the DPR source of my project:

program X;

uses
  Vcl.Forms,
  uMain in 'uMain.pas' {MainForm},
  uFooA in 'uFooA.pas',
  uFooB in 'uFooB.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;

end.

My issue is that this simply isn't the order in which Initialization blocks are executed.

How it should be |  How it actually is
                 | 
  1. uMain       |     1.uFooA
  2. uFooA       |     2.uFooB  
  3. uFooB       |     3.uMain

I would love to provide a SSCCE but I simply am not able to re-produce this issue on a fresh project.

I've tried re-building the project with no success.

What am I missing?

Was it helpful?

Solution

Even though there is a rigorous way in which the compiler determines initialisation, it's very difficult for a human to accurately figure out and control when there are many units with many dependencies.

E.g. Your DPR may use UnitA, UnitB, UnitC; but if UnitA has dependencies on UnitB then UnitB has to be initialised first.

Admittedly, the feature of units having initialization and finalization sections can make adding functionality as simple as "add the unit". Although this seems great, in reality, on really large projects it tends to get in the way. Personally I consider the "feature" to be quite horrible.

The best and most reliable way to control the inialisation sequence of your units is to do so explicitly. E.g.

program X;

uses
  Vcl.Forms,
  uMain in 'uMain.pas' {MainForm},
  uFooA in 'uFooA.pas',
  uFooB in 'uFooB.pas';

{$R *.res}

begin
  Init_uMain;
  Init_uFooA;
  Init_uFooB;

  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;

  Finalise_uFooB;
  Finalise_uFooA;
  Finalise_uMain;
end.

Obviously the above code lacks appropriate try..finallys and would get messy with many units needing initialisation. However, there are other techniques that can be applied to keep things manageable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top