← board

Resolve Delphi dotted unit-scope names

The measurement

DWScript, --mimic-fpc -Mdelphi, HEAD af8b53310 / compiler 450d7de641d8:

unit verdict
dwsStrings compiles clean
dwsXPlatform dwsUtils dwsErrors dwsExprs dwsCompiler dwsRTTIExposer unit source not found: system.classes
dwsSymbols unit source not found: system.sysutils

One wall, seven units, and the eighth proves the rest of the pipeline is fine.

Why this is a feature and not a compat bug

fpc 3.2.2 -Mdelphi on uses System.SysUtils, System.Classes; answers Fatal: Can't find unit System.SysUtils used by ns. Tried and rejected as workarounds on the oracle itself: -UaSystem.SysUtils=sysutils is an illegal parameter in 3.2.2, and -FNSystem does not help because FPC's namespaces require the unit to declare one. So our oracle cannot do this either, and per the goal file that puts it outside compat entirely. It earns its place on reach: the Delphi half of the real-world Object Pascal corpus spells its uses this way, and today none of it gets past line 3.

The proposed shape, and the shape to avoid

pxxlib.cfg already exists for precisely this problem — a build profile scoped to one library's directory tree, applied without CLI flags and without editing the library's source, with the scope following the unit being compiled so sibling libraries never see each other's settings. A unitalias key belongs there:

unitalias System.Classes=classes
unitalias System.SysUtils=sysutils

Do not implement it as a blanket "strip any dotted prefix". Two units a Delphi program deliberately keeps apart would silently become one, and the failure would be a wrong unit rather than a diagnostic — the class of defect this repo is most careful about. An explicit table also documents, per corpus target, exactly which mappings that target needed.

Scope note

This unblocks the DWScript core and any other Delphi-namespaced tree. It does not unblock dwsRTTIExposer, which needs Delphi extended RTTI (TRttiContext and 14 other TRtti* classes) that fpc 3.2.2 only partly has and pxx does not have at all — see [[feature-embed-dwscript-rtti]] for that measurement.

LANDED 2026-09-05 (frankH) — 731463e70

unitalias <Dotted.Name>=<unit> in a pxxlib.cfg. Registration and lookup in paslexer.inc beside the manifest's other directives; the table in defs.inc; one call in ParseUsesUnit (pasparser_proc.inc) applied where lo/cName are computed, before anything records an identity, so System.Classes and Classes dedupe as ONE compiled unit rather than two — which they are.

Scoped by the manifest that declared it, not globally. The row stores the manifest path alongside it, and is honoured only while resolving a uses written in a unit whose own nearest manifest is that same file. That is the rule define/undef/mode already follow, and storing the path means the table needs no save-and-restore around each unit.

Inert without a row. PxxUnitAliasCount = 0 exits before the cached manifest walk, so every existing compilation takes the same path it did.

What it moved, measured

DWScript, --mimic-fpc -Mdelphi, eight probed units:

before after
1 clean, 7 stop at unit source not found: system.classes / system.sysutils 8 get past it; all 8 now stop at lclintf, 50+ lines further in

lclintf is not this ticket's problem and is not a pxx gap: dwsXPlatform.pas takes {$IFDEF FPC}{$ELSE} , LCLIntf, so telling DWScript we are FPC sends it into Lazarus, while not telling it sends it into the Delphi RTL (System.IOUtils, Posix.*). Recorded on [[feature-embed-dwscript-rtti]].

The residual — MEASURED THE SAME DAY, AND IT IS NOT ONE

System.Move, System.Length, System.SetLength, System.FillChar appear 54, 6, 3 and 3 times in DWScript. Those are qualified identifiers, not unit names, and this feature does not touch them. This section first said nobody had measured whether pxx accepts that spelling and that the question had no owner. Measured immediately rather than left as an open question, because an ownerless residual in a done/ ticket is exactly the kind of thing that gets re-derived as a blocker a month later:

System.SetLength(s, 1);   { h  }
System.Length(s)          { 1  }
System.Move(a, b, 4);     { 7  }
SysUtils.IntToStr(42)     { 42 }

pxx already accepts all four and matches fpc 3.2.2 -Mdelphi output for output. There is nothing to do here and nothing to file.

Gate

gate.sh quick GREEN 17/17 including the FPC seed canary and the self-host fixedpoint. make test-core was NOT run and is not claimed: the change is inert without a manifest row, and the three new rows were each verified by direct invocation with the exact strings the Makefile greps for.