A unit file consists of basically five parts:
The header consists of a sequence of 20 bytes, together they give some information about the unit file, the compiler version that was used to generate the unit file, etc. The complete layout can be found in table (A.1). The header is generated by the compiler, and changes only when the compiler changes. The current and up-to-date header definition can be found in the files.pas source file of the compiler. Look in this file for the unitheader constant declaration.
Byte | What is stored |
0..3 | The letters 'PPU' in upper case. This acts as a check. |
4..6 | The unit format as a 3 letter sequence : e.g. '0','1,'2' for format 12. |
7,8 | The compiler version and release numbers as bytes. |
9 | The target OS number. |
10 | Unit flags. |
11..14 | Checksum (as a longint). |
15,16 | unused (equal to 255). |
17..20 | Marks start of unit file. |
After the header, in the second part, first the list of all source files for the unit is written. Each name is written as a direct copy of the string in memory, i.e. a length bytes, and then all characters of the string. This list includes any file that was included in the unit source with the {$i file} directive. The list is terminated with a $ff byte marker. After this, the list of units in the uses clause is written, together with their checksums. The file is written as a string, the checksum as a longint (i.e. four bytes). Again this list is terminated with a $ff byte marker.
After that, in the third part, the definitions of all types, variables, constants, procedures and functions are written to the unit file.
They are written in the following manner: First a byte is written, which determines the kind of definition that follows. then follows, as a series of bytes, a type-dependent description of the definition. The exact byte order for each type can be found in table (A.2)
hline Type | Start byte | Size | Stored fields | |||||||
Pointer | 3 | 4 | Reference to the type pointer points to. | |||||||
Base type | 2 | 9 |
| |||||||
Array type | 5 | 16 |
| |||||||
Procedure | 6 | ? |
| |||||||
Procedural type | 21 | ? |
| |||||||
String | 9 | 1 | 1 byte containing the length of the string. | |||||||
Record | 15 | variable |
| |||||||
Class | 18 | variable |
| |||||||
file | 16 | 1(+4) |
| |||||||
Enumeration | 19 | 4 | Biggest element. | |||||||
set | 20 | 5 |
| |||||||
This list of definitions is again terminated with a $ff byte marker.
After that, a list of symbols is given, together with a reference to a definition. This represents the names of the declarations, and the definition they refer to.
A reference consists of 2 words : the first word indicates the unit number (as it appears in the uses clause), and the second word is the number of the definition in that unit. A nil reference is stored as $ffffffff.
After this follows again a $ff byte terminated list of filenames: The names of the units in the uses clause of the implementation section.