Sign in Join
Wiki copytemporary

System unit: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11In Free Pascal the **System** unit is the unit that is included by *every* program. FPC's [[RTL|run-time library]] comes with a System unit where most, if not all of its functionalities work on every available [[Platform list|platform]].
22
33Also depending on the platform it's not true that no further unit is added, because for example on Windows the **SysInit** unit is also used, because that contains the entry point for the binary.
44
55## Compilation of System unit
66
77For quite some time already FPC automatically applies the -Us switch to the unit named System, so you don't need the -Us switch. The -Us switch tells the compiler that only basic type definitions are being made. Types such as [[Integer]] are not yet available.
88
99### Mandatory tasks of System unit
1010
1111If you attempt to create your own system unit, you'll incrementally notice what the compiler needs or what the generated code expects. On a Linux target, the minimal system unit has to contain:
1212
1313``` pascal
1414unit system;
1515
1616interface
1717```
1818
1919The type **hresult** must be defined, for example:
2020
2121``` pascal
2222type
2323 hresult = LongInt;
2424```
2525
2626The identifier **operatingsystem_result** has to be declared. The data stored at that position are communicated to the operating system as return value. Whether **hresult** and **operatingsystem_result** are defined in the "interface" section is irrelevant. However, it is very plausible to put those into the "interface" section, so programs using this system unit can manipulate those.
2727
2828``` pascal
2929var
3030 ExitCode: hresult = 0; export name 'operatingsystem_result';
3131
3232implementation
3333```
3434
3535Here comes to light what the system responsibilities are: It has to (or should) initialize units, that means call every unit's [[Initialization]] routines. For that the label **FPC_INITIALIZEUNITS** has to be defined.
3636
3737``` pascal
3838procedure InitializeUnits; alias: 'FPC_INITIALIZEUNITS';
3939begin
4040end;
4141```
4242
4343Also the label **FPC_DO_EXIT** has to be defined. Here, system unit programmers have the chance to finalize units.
4444
4545``` pascal
4646procedure doExit; alias: 'FPC_DO_EXIT';
4747begin
4848end;
4949
5050end.
5151```
5252
5353Furthermore FPC will possibly complain the unit FPIntRes is missing. So create a file fpintres.pas:
5454
5555``` pascal
5656unit FPIntRes;
5757interface
5858implementation
5959end.
6060```
6161
6262After doing so, you can compile your system unit (flag -Us is not needed), or directly create an empty program and compile it to examine the impact on the binary's size. On a x86-64 Linux target the executable had a size of 2.7 Kbytes. The big trade-off is no convenience. All functionality that can't be “implemented” by the compiler is gone. For example [[Addr]] or [[Ord]] still work, while Sin() or Random() are not available. Confer the procedure **create_intern_symbols** in "compiler/psystem.pas".
6363
6464> **Note:** Depending on what your program uses, there might *other* mandatory tasks, too. Especially OOP won't work without a functional ObjPas unit.
6565
6666### Initialization and finalization of units
6767
6868For those who are curious, how to implement FPC_INITIALIZEUNITS: FPC puts into every program's data section a INITFINAL table. Compiling a program with the "-al" flag will retain the Assembler file "*.s". Examining this Assembler file, you will encounter something like:
6969
7070``` asm
7171.section .data.n_INITFINAL
7272 .balign 8
7373.globl INITFINAL
7474 .type INITFINAL,@object
7575INITFINAL:
7676 .quad 1,0
7777 .quad INIT$_$SOMEUNIT
7878 .quad FINALIZE$_$SOMEUNIT
7979```
8080
8181For further investigations have a glimpse at an actual implementation: ["rtl/inc/system.inc"](https://gitlab.com/freepascal.org/fpc/source/-/blob/main/rtl/inc/system.inc).
8282
8383> **Note:** In general, implementing an “own” system unit is a stupid idea. There is “smart-linking” if [[Size Matters|size matters]].
8484
8585### Other issues with compilation
8686
8787- Q: Now FPC wants to compile the ObjPas unit.
8888- A: That is because your project's mode is set to ObjFPC (Lazarus will pass a -MObjFPC parameter to the compiler then) which automatically leads to an insertion of the ObjPas unit. Either change your project's mode in Project Settings -\> Compiler Settings -\> Parsing or add a {\$mode fpc} to your main program file.
8989
9090------------------------------------------------------------------------
9191
9292- Q: Now FPC cannot find this:
9393
94-`Unknown compilerproc "fpc_initializeunits". Check if you use the correct run time library.`
94+```text
95+Unknown compilerproc "fpc_initializeunits". Check if you use the correct run time library.
96+```
9597
9698- A: You need to add a
9799
98100``` pascal
99101 procedure fpc_initializeunits; compilerproc;
100102```
101103
102104both in the interface and implementation section.
103105
104106------------------------------------------------------------------------
105107
106108- Q: I am stuck, FPC says:
107109
108-`Internal type "TEXCEPTADDR" was not found`
110+``` pascal
111+Internal type "TEXCEPTADDR" was not found
112+```
109113
110114- A: The compiler expects some system defined types to be defined when parsing a subroutine such as the implementation section of System. This means you have to add some type definitions to System. It appears that this check was added to 3.2.0.
111115
112116## Example of System unit
113117
114118The example is made by user Okoba [at forum](https://forum.lazarus.freepascal.org/index.php?topic=49434.msg367677#msg367677).
115119
116120File system.pas:
117121
118122``` pas
119123unit system;
120124{$MODE FPC}
121125interface
122126
123127type
124128 hresult = LongInt;
125129 DWord = LongWord;
126130 Cardinal = LongWord;
127131 Integer = SmallInt;
128132 UInt64 = QWord;
129133 TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat, tkSet,
130134 tkMethod, tkSString, tkLString, tkAString, tkWString, tkVariant, tkArray,
131135 tkRecord, tkInterface, tkClass, tkObject, tkWChar, tkBool, tkInt64, tkQWord,
132136 tkDynArray, tkInterfaceRaw, tkProcVar, tkUString, tkUChar, tkHelper, tkFile,
133137 tkClassRef, tkPointer);
134138
135139type
136140 jmp_buf = packed record
137141 rbx, rbp, r12, r13, r14, r15, rsp, rip: QWord;
138142 {$IFDEF win64}
139143 rsi, rdi: QWord;
140144 xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15: record
141145 m1, m2: QWord;
142146 end;
143147
144148 mxcsr: LongWord;
145149 fpucw: word;
146150 padding: word;
147151 {$ENDIF win64}
148152 end;
149153
150154 Pjmp_buf = ^jmp_buf;
151155 PExceptAddr = ^TExceptAddr;
152156 TExceptAddr = record
153157 buf: Pjmp_buf;
154158 next: PExceptAddr;
155159 {$IFDEF CPU16}
156160 frametype: SmallInt;
157161 {$ELSE CPU16}
158162 frametype: LongInt;
159163 {$ENDIF CPU16}
160164 end;
161165
162166 PGuid = ^TGuid;
163167 TGuid = packed record
164168 case Integer of
165169 1:
166170 (Data1: DWord;
167171 Data2: word;
168172 Data3: word;
169173 Data4: array [0 .. 7] of byte;
170174 );
171175 2:
172176 (D1: DWord;
173177 D2: word;
174178 D3: word;
175179 D4: array [0 .. 7] of byte;
176180 );
177181 3:
178182 ( { uuid fields according to RFC4122 }
179183 time_low: DWord; // The low field of the timestamp
180184 time_mid: word; // The middle field of the timestamp
181185 time_hi_and_version: word;
182186 // The high field of the timestamp multiplexed with the version number
183187 clock_seq_hi_and_reserved: byte;
184188 // The high field of the clock sequence multiplexed with the variant
185189 clock_seq_low: byte; // The low field of the clock sequence
186190 node: array [0 .. 5] of byte; // The spatially unique node identifier
187191 );
188192 end;
189193
190194var
191195 ExitCode: hresult = 0; export name 'operatingsystem_result';
192196
193197procedure fpc_initializeunits; compilerproc;
194198
195199procedure fpc_do_exit; compilerproc;
196200
197201implementation
198202
199203procedure fpc_initializeunits;
200204begin
201205end;
202206
203207procedure fpc_do_exit;
204208begin
205209end;
206210
207211end.
208212```
209213
210214File sysinit.pas:
211215
212216``` Pascal
213217unit sysinit;
214218{$MODE FPC}
215219
216220interface
217221
218222procedure _FPC_mainCRTStartup; stdcall; public name '_mainCRTStartup';
219223
220224implementation
221225
222226procedure _FPC_mainCRTStartup; stdcall;
223227begin
224228end;
225229
226230end.
227231```
228232
229233File fpintres.pas:
230234
231235``` Pascal
232236unit FPIntRes;
233237{$MODE FPC}
234238
235239interface
236240implementation
237241end.
238242```
239243
240244## Comparative remarks
241245
242246Other compilers such as [[GNU Pascal]] or [[Delphi]] use similar constructs, but to varying extent, and the file is not necessarily named "system.pas".
243247
244248## See also
245249
246250- FPC RTL System unit reference
247251- [[System unit structure]], some explanation about the distributed system unit
248252- [[Minimal RTL]]
249253- [[RTL development articles]]
250254
251255---
252256*From the Free Pascal wiki, page "System unit", as it stood on 2022-01-07 after a change by Alextp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
253257Category: Code

Back to history