Skip to content

Commit 285d7c6

Browse files
committed
Repo Update
- Switched from kyx0r single-file TCC to official TinyCC repository for better runtime support - Fixed critical workflow state bug preventing multiple CompileString/AddFile calls in sequence - AddFile and CompileString now correctly allow multiple calls in wsConfigured or wsCompiled states - This fix enables proper multi-file compilation workflow (e.g., compile to .o, then link with main) - Official TCC provides proper libtcc1.a runtime library and startup code for EXE generation - Added comprehensive documentation distinguishing Reset() vs Clear() methods - Reset() now documented to preserve callbacks while Clear() removes all configuration - Improved XML documentation for both methods with clear examples of use cases
1 parent 4fc126b commit 285d7c6

File tree

4 files changed

+158
-63
lines changed

4 files changed

+158
-63
lines changed

examples/testbed/Testbed.dpr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
------------------------------------------------------------------------------
4242
4343
This library uses the following open-source libraries:
44-
* tinycc - https://github.com/kyx0r/tinycc
44+
* tinycc - https://github.com/TinyCC/tinycc
4545
4646
===============================================================================}
4747

examples/testbed/UTestbed.pas

Lines changed: 102 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
------------------------------------------------------------------------------
4242
4343
This library uses the following open-source libraries:
44-
* tinycc - https://github.com/kyx0r/tinycc
44+
* tinycc - https://github.com/TinyCC/tinycc
4545
4646
===============================================================================}
4747

@@ -66,63 +66,27 @@ procedure Pause();
6666
WriteLn;
6767
end;
6868

69-
procedure Test01();
70-
type
71-
TAddFunc = function(AInt1, AInt2: Integer): Integer; cdecl;
72-
const
73-
// Intentionally broken: "int1" instead of "int"
74-
CCode = 'int add(int1 a, int b) { return a + b; }';
69+
procedure ShowErrors(const ACompiler: TDelphiC);
7570
var
76-
LDC: TDelphiC;
77-
LAddFunc: TAddFunc;
7871
LErrors: TArray<TDCError>;
7972
LError: TDCError;
8073
begin
81-
WriteLn('=== Test01: Error Handling ===');
82-
LDC := TDelphiC.Create();
83-
try
84-
LDC.SetPrintCallback(
85-
nil,
86-
procedure (const AText: string; const AUserData: Pointer)
87-
begin
88-
WriteLn('[TCC] ', AText);
89-
end
90-
);
91-
92-
LDC.SetOuput(opMemory);
93-
94-
WriteLn('Compiling code with intentional error...');
95-
if not LDC.CompileString(CCode) then
96-
begin
97-
WriteLn('Compilation failed (as expected)');
98-
WriteLn;
99-
LErrors := LDC.GetErrors();
100-
WriteLn('Captured ', Length(LErrors), ' error(s):');
101-
for LError in LErrors do
102-
begin
103-
WriteLn(' File: ', LError.Filename);
104-
WriteLn(' Line: ', LError.Line);
105-
WriteLn(' Type: ', GetEnumName(TypeInfo(TDCErrorType), Ord(LError.ErrorType)));
106-
WriteLn(' Msg: ', LError.Message);
107-
WriteLn;
108-
end;
109-
end
110-
else
111-
begin
112-
WriteLn('ERROR: Compilation should have failed!');
113-
if LDC.Relocate() then
114-
begin
115-
LAddFunc := LDC.GetSymbol('add');
116-
if Assigned(LAddFunc) then
117-
WriteLn('Result: ', LAddFunc(10, 20));
118-
end;
119-
end;
120-
finally
121-
LDC.Free();
74+
WriteLn;
75+
LErrors := ACompiler.GetErrors();
76+
if Length(LErrors) = 0 then Exit;
77+
78+
WriteLn('Captured ', Length(LErrors), ' error(s):');
79+
for LError in LErrors do
80+
begin
81+
WriteLn(' File: ', LError.Filename);
82+
WriteLn(' Line: ', LError.Line);
83+
WriteLn(' Type: ', GetEnumName(TypeInfo(TDCErrorType), Ord(LError.ErrorType)));
84+
WriteLn(' Msg: ', LError.Message);
85+
WriteLn;
12286
end;
12387
end;
12488

125-
procedure Test02();
89+
procedure Test01();
12690
type
12791
TAddFunc = function(AInt1, AInt2: Integer): Integer; cdecl;
12892
const
@@ -173,10 +137,97 @@ procedure Test02();
173137
WriteLn('Failed to retrieve symbol "add"');
174138
end;
175139
finally
140+
ShowErrors(LDC);
176141
LDC.Free();
177142
end;
178143
end;
179144

145+
procedure Test02;
146+
const
147+
CAddCode = 'int add(int a, int b) { return a + b; }';
148+
CMainCode = '#include <stdio.h>' + sLineBreak +
149+
'int add(int, int);' + sLineBreak +
150+
'int main() {' + sLineBreak +
151+
' int result = add(2, 3);' + sLineBreak +
152+
' printf("Result: %d\n", result);' + sLineBreak +
153+
' return 0;' + sLineBreak +
154+
'}';
155+
var
156+
LCompiler: TDelphiC;
157+
158+
begin
159+
WriteLn('=== Test02: Compile and Link to EXE ===');
160+
LCompiler := TDelphiC.Create();
161+
try
162+
LCompiler.SetPrintCallback(
163+
nil,
164+
procedure (const AText: string; const AUserData: Pointer)
165+
begin
166+
WriteLn('[TCC] ', AText);
167+
end
168+
);
169+
170+
// Compile unit1 to object file
171+
WriteLn('Setting output mode to OBJ...');
172+
if not LCompiler.SetOuput(opOBJ) then
173+
begin
174+
WriteLn('Failed to set output mode to OBJ');
175+
Exit;
176+
end;
177+
178+
WriteLn('Compiling add function to object file...');
179+
if not LCompiler.CompileString(CAddCode) then
180+
begin
181+
WriteLn('Failed to compile add function');
182+
Exit;
183+
end;
184+
185+
WriteLn('Outputting unit1.o...');
186+
if not LCompiler.OutputFile('unit1.o') then
187+
begin
188+
WriteLn('Failed to output unit1.o');
189+
Exit;
190+
end;
191+
192+
// Reset and link everything
193+
WriteLn('Resetting compiler...');
194+
LCompiler.Reset();
195+
196+
WriteLn('Setting output mode to EXE...');
197+
if not LCompiler.SetOuput(opEXE) then
198+
begin
199+
WriteLn('Failed to set output mode to EXE');
200+
Exit;
201+
end;
202+
203+
WriteLn('Adding unit1.o...');
204+
if not LCompiler.AddFile('unit1.o') then
205+
begin
206+
WriteLn('Failed to add unit1.o');
207+
Exit;
208+
end;
209+
210+
WriteLn('Compiling main program...');
211+
if not LCompiler.CompileString(CMainCode) then
212+
begin
213+
WriteLn('Failed to compile main program');
214+
Exit;
215+
end;
216+
217+
WriteLn('Outputting program.exe...');
218+
if not LCompiler.OutputFile('program.exe') then
219+
begin
220+
WriteLn('Failed to output program.exe');
221+
Exit;
222+
end;
223+
224+
WriteLn('SUCCESS: program.exe created');
225+
finally
226+
ShowErrors(LCompiler);
227+
LCompiler.Free();
228+
end;
229+
end;
230+
180231
procedure RunTests();
181232
var
182233
LNum: Integer;

src/DelphiC.pas

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
------------------------------------------------------------------------------
4242
4343
This library uses the following open-source libraries:
44-
* tinycc - https://github.com/kyx0r/tinycc
44+
* tinycc - https://github.com/TinyCC/tinycc
4545
4646
===============================================================================}
4747

@@ -337,15 +337,52 @@ TCallback<T> = record
337337
procedure ClearErrors();
338338

339339
/// <summary>
340-
/// Resets the compiler to initial state, destroying and recreating the TCC context.
340+
/// Resets the compiler to initial state while preserving callback registrations.
341341
/// </summary>
342342
/// <remarks>
343-
/// This allows reuse of the same TDelphiC instance for multiple compilation sessions.
344-
/// All previous configuration, compilation state, and symbols are lost.
343+
/// <para>
344+
/// Destroys and recreates the TCC compilation context, allowing reuse of the
345+
/// same TDelphiC instance for multiple compilation sessions.
346+
/// </para>
347+
/// <para>
348+
/// All previous configuration, compilation state, and symbols are lost.
349+
/// </para>
350+
/// <para>
351+
/// <b>Preserved:</b> Print callback registration (set via SetPrintCallback)
352+
/// </para>
353+
/// <para>
354+
/// <b>Cleared:</b> Output type, compiler options, include/library paths,
355+
/// defined symbols, compiled code, and workflow state
356+
/// </para>
357+
/// <para>
358+
/// Use <see cref="Clear"/> if you also want to remove callback registrations.
359+
/// </para>
345360
/// </remarks>
346361
/// <exception cref="Exception">Raised if TCC reinitialization fails</exception>
347362
procedure Reset();
348363

364+
/// <summary>
365+
/// Completely resets the compiler to pristine initial state, clearing all
366+
/// configuration including callback registrations.
367+
/// </summary>
368+
/// <remarks>
369+
/// <para>
370+
/// Performs the same reset as <see cref="Reset"/> but also clears all
371+
/// callback registrations, returning the instance to a completely clean state
372+
/// as if freshly created.
373+
/// </para>
374+
/// <para>
375+
/// <b>Cleared:</b> Print callback registration, output type, compiler options,
376+
/// include/library paths, defined symbols, compiled code, and workflow state
377+
/// </para>
378+
/// <para>
379+
/// Use this when you want a completely fresh start without any residual
380+
/// configuration. Use <see cref="Reset"/> if you want to keep your callbacks.
381+
/// </para>
382+
/// </remarks>
383+
/// <exception cref="Exception">Raised if TCC reinitialization fails</exception>
384+
procedure Clear();
385+
349386
/// <summary>
350387
/// Sets a callback function to receive TCC error and warning messages.
351388
/// </summary>
@@ -854,9 +891,6 @@ procedure TDelphiC.FreeState();
854891
begin
855892
tcc_delete(FState);
856893
FState := nil;
857-
858-
FPrintCallback.Handler := nil;
859-
FPrintCallback.UserData := nil;
860894
end;
861895
end;
862896

@@ -913,6 +947,16 @@ procedure TDelphiC.Reset();
913947
NewState();
914948
end;
915949

950+
procedure TDelphiC.Clear();
951+
begin
952+
Reset();
953+
954+
// Reset callbacks
955+
FPrintCallback.Handler := nil;
956+
FPrintCallback.UserData := nil;
957+
end;
958+
959+
916960
function TDelphiC.AddIncludePath(const APathName: string): Boolean;
917961
begin
918962
// Allow in new or configured state, but not after compilation
@@ -1081,14 +1125,14 @@ function TDelphiC.CompileString(const ACode, AFilename: string): Boolean;
10811125
LCode: string;
10821126
begin
10831127
// Must set output type first, and not be past compilation stage
1084-
if not FOutputSet or (FWorkflowState > wsConfigured) then
1128+
if not FOutputSet or (FWorkflowState <> wsConfigured) and (FWorkflowState <> wsCompiled) then
10851129
begin
10861130
Result := False;
10871131
Exit;
10881132
end;
10891133

10901134
LCode := '#line 1 "' + AFilename + '"' + #13#10 + ACode;
1091-
Result := tcc_compile_string(FState, AsUTF8(LCode)) >= 0;
1135+
Result := Boolean(tcc_compile_string(FState, AsUTF8(LCode)) >= 0);
10921136
if Result then
10931137
FWorkflowState := wsCompiled;
10941138
end;
@@ -1106,7 +1150,7 @@ function TDelphiC.CompileFile(const AFilename: string): Boolean;
11061150
function TDelphiC.AddFile(const AFilename: string): Boolean;
11071151
begin
11081152
// Must set output type first, and not be past compilation stage
1109-
if not FOutputSet or (FWorkflowState > wsConfigured) then
1153+
if not FOutputSet or (FWorkflowState <> wsConfigured) and (FWorkflowState <> wsCompiled) then
11101154
begin
11111155
Result := False;
11121156
Exit;
@@ -1565,7 +1609,7 @@ function LoadTCCDLL(out AError: string): Boolean;
15651609
Result := False;
15661610
if LTCCDllHandle <> 0 then Exit(True);
15671611

1568-
LTCCDllHandle := LoadLibrary('tcc.dll');
1612+
LTCCDllHandle := LoadLibrary('libtcc.dll');
15691613
if LTCCDllHandle = 0 then
15701614
begin
15711615
AError := 'Failed to load TCC DLL';

src/DelphiC.res

161 KB
Binary file not shown.

0 commit comments

Comments
 (0)