In our organisation we would like to force layered structure of source code. Each unit would be in certain "level" and units would be able to use only units in same or lower level.
Example:
Suppose we have these units: L1_A.pas
, L1_B.pas
, L2_C.pas
, L2_D.pas
, L3_E.pas
(LX_
means "level X").
L1_A
and L1_B
can use each other. L2_C
and L2_D
can use all L1_*
units and each other. L3_E
can use all other units.
If L1_*
unit tried to use either L2_*
unit or L3_*
unit, we need to abort compilation and produce some error ("Unit in lower level tried to use unit in higher level").
Have we coded in C (or other language with preprocessor), we would for example define LEVEL_1
, LEVEL_2
, LEVEL_3
constants and in all 1st (resp. 2nd) level units check if eihter LEVEL_2
or LEVEL_3
(resp. LEVEL_3
) constants were defined in which case we would emit relevant error.
Delphi defines (defined by {$DEFINE}
) don't have effect outside unit in which they were defined. Named constants and constant expressions can be used outside, but which one we see depends on the order of units in uses
(ie if L1_A
defines const Level=1
and L2_C
const Level=2
and L1_B
contains using L2_C, L1_A
than Level
in L1_B
would be 2
).
I came up only with naming convention [LX_Unit.pas
(or LX.Unit.pas), where X
is level and Unit
is "real" unit name], and checking with a script in svn
commit hook.
We would like to use only basic Delphi (no external tools).
But you can check for constants. It doesn't matter if several units define the same one, and what their type or value is, as long as its name matches a certain pattern. In a way, such a constant is like an "exported" $define
:
const
Level3 = 3;
uses
X, Y, Z; // Z.Level3 hides Y.Level3, but that doesn't matter.
{$IF declared(Level3)}
As the documentation states:
Declared returns True if the argument passed to it is a valid declared Delphi identifier visible within the current scope.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With