The key words there are "if the compiler decides".
Yes, that's the important part.
* Program X uses unit Y which includes file Z, and file Z uses unit T.
Nitpicking: it's
always unit
Y that
uses unit
T, but it's file
Z that
contains the
uses-clause (this is an important point, because the compiler keeps track of used units and symbols and such based on units, not based on files)
* A change to (only) Z will not cause Y or X to be recompiled, since the names and attributes of included files are not stored in a .ppu file.
As long as the system works correctly a change to
Z will trigger a recompilation of
Y (sidenote: the main program file, or to be precise the file provided on the command line - after all it could be a unit as well - is
always compiled), because the compiler
does store the included files and their timestamps in the PPU.
Take the following example:
// trecompile.pp
program trecompile;
uses
urecompile;
begin
end.
// urecompile.pp
unit urecompile;
{$mode objfpc}{$H+}
interface
{$I irecompile.inc}
implementation
end.
// irecompile.inc
uses
{$I irecompile2.inc}
Classes;
// irecompile2.inc
{SysUtils,}
If you now compile
trecompile.pp you will see the following output:
PS D:\fpc\git> fpc -FEtestoutput .\fpctests\trecompile.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling .\fpctests\trecompile.pp
Compiling .\fpctests\urecompile.pp
Linking testoutput\trecompile.exe
24 lines compiled, 0.1 sec, 148000 bytes code, 6548 bytes data
If you compile it again without any changes the output will be as following:
PS D:\fpc\git> fpc -FEtestoutput .\fpctests\trecompile.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling .\fpctests\trecompile.pp
Linking testoutput\trecompile.exe
8 lines compiled, 0.1 sec, 148000 bytes code, 6548 bytes data
As you can see the line
Compiling .\fpctests\urecompile.pp is missing, because the compiler determined that
urecompile.pp is up to date.
You can also use
ppudump urecompile.ppu and you will see the following (among other information):
Interface section
------------------
Module Name: urecompile
Source file 1 : urecompile.pp 2022/06/02 08:58:06
Source file 2 : irecompile.inc 2022/06/02 08:59:52
Source file 3 : irecompile2.inc 2022/06/02 09:00:20
Uses unit: System (Crc: D86E0595, IntfcCrc: 01C77D16, IndCrc: BDD566AD)
Uses unit: objpas (Crc: 869382B2, IntfcCrc: 28EE26C5, IndCrc: AB9908A2)
Uses unit: Classes (Crc: 5FF4CBD7, IntfcCrc: DBC85DDC, IndCrc: 2CAFF89A)
DerefMapsize: 1
DerefMap[0] = SYSTEM
Derefdata length: 27
If you now change
irecompile2.inc (by removing the swirly brackets) you will see this:
PS D:\fpc\git> fpc -FEtestoutput .\fpctests\trecompile.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling .\fpctests\trecompile.pp
Compiling .\fpctests\urecompile.pp
Linking testoutput\trecompile.exe
24 lines compiled, 0.1 sec, 148000 bytes code, 6548 bytes data
So here the compiler decided to recompile
urecompile.pp, because it successfully detected the changed file.
So in this specific example everything is as it should be.
* A change to T will always cause Y and X to be recompiled (hence Z to be reread), since the names and attributes of used files are stored in a .ppu file.
Here you didn't pay attention to Pascal 101: a unit is only recompiled if something significant of a used unit changed. Mainly this means information from the unit's interface, but sometimes this is also the case if the code of some function declared with
inline changed (this is still the source of quite some headaches in the compiler and ideally the compiler should also trigger this if a generic implementation is changed...).
So if you change something in the implementation of
T then
Y likely won't be recompiled (and
X will always be as mentioned above), but if you change something in the interface section of
T it is very likely that
Y will be recompiled. I say likely, because if you only change a typo in a comment and that change doesn't lead to a change of the file position for the remainder of the code (meaning for example that you didn't insert or remove a line) then the relevant content of the unit (from the compiler's PoV) is still considered the same and thus the compiler doesn't see the need to recompile
Y.
To come back to your problem: as you see it
should work correctly. However we know from past experience that
something there is fishy when multiple include files are used, but we've not yet been able to pinpoint the problem. Or maybe it was indeed solved already. That's the problem: we don't have a reproducible case and thus don't know whether the problem has been solved or not.