1 {
2 This file is part of the Free Pascal Integrated Development Environment
3 Copyright (c) 1998 by Berczi Gabor
4
5 Compiler call routines for the IDE
6
7 See the file COPYING.FPC, included in this distribution,
8 for details about the copyright.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 **********************************************************************}
15 {$i globdir.inc}
16 unit FPCompil;
17
18 {2.0 compatibility}
19 {$ifdef VER2_0}
20 {$macro on}
21 {$define resourcestring := const}
22 {$endif}
23
24 interface
25
26 { don't redir under linux, because all stdout (also from the ide!) will
27 then be redired (PFV) }
28 { this should work now correctly because
29 RedirDisableAll and RedirEnableAll function are added in fpredir (PM) }
30
31 { $define VERBOSETXT}
32
33 {$mode objfpc}
34
35 uses
36 { We need to include the exceptions from SysUtils, but the types from
37 Objects need to be used. Keep the order SysUtils,Objects }
38 SysUtils,
39 Objects,
40 FInput,
41 Drivers,Views,Dialogs,
42 WUtils,WViews,WCEdit,
43 FPSymbol,
44 FPViews;
45
46 type
47 TCompileMode = (cBuild,cMake,cCompile,cRun);
48
49 type
50 PCompilerMessage = ^TCompilerMessage;
51 TCompilerMessage = object(TMessageItem)
GetTextnull52 function GetText(MaxLen: Sw_Integer): String; virtual;
53 end;
54
55 PCompilerMessageListBox = ^TCompilerMessageListBox;
56 TCompilerMessageListBox = object(TMessageListBox)
GetPalettenull57 function GetPalette: PPalette; virtual;
58 procedure SelectFirstError;
59 end;
60
61 PCompilerMessageWindow = ^TCompilerMessageWindow;
62 TCompilerMessageWindow = object(TFPWindow)
63 constructor Init;
64 procedure HandleEvent(var Event: TEvent); virtual;
GetPalettenull65 function GetPalette: PPalette; virtual;
66 procedure Close;virtual;
67 destructor Done; virtual;
68 procedure SizeLimits(var Min, Max: TPoint); virtual;
69 procedure AddMessage(AClass: longint;const Msg, Module: string; Line, Column: longint);
70 procedure ClearMessages;
71 constructor Load(var S: TStream);
72 procedure Store(var S: TStream);
73 procedure SetState(AState: Word; Enable: Boolean); virtual;
74 procedure UpdateCommands; virtual;
75 private
76 {CompileShowed : boolean;}
77 {Mode : TCompileMode;}
78 MsgLB : PCompilerMessageListBox;
79 {CurrST,
80 InfoST : PColorStaticText;}
81 end;
82
83 PCompilerStatusDialog = ^TCompilerStatusDialog;
84 TCompilerStatusDialog = object(TCenterDialog)
85 ST : PAdvancedStaticText;
86 KeyST : PColorStaticText;
87 starttime : real;
88 constructor Init;
89 destructor Done;virtual;
90 procedure Update;
91 procedure SetStartTime(r : real);
92 end;
93
94 TFPInputFile = class(tinputfile)
95 constructor Create(AEditor: PFileEditor);
96 protected
fileopennull97 function fileopen(const filename: ansistring): boolean; override;
fileseeknull98 function fileseek(pos: longint): boolean; override;
filereadnull99 function fileread(var databuf; maxsize: longint): longint; override;
fileeofnull100 function fileeof: boolean; override;
fileclosenull101 function fileclose: boolean; override;
102 procedure filegettime; override;
103 private
104 Editor: PFileEditor;
105 S: PStream;
106 end;
107
108 const
109 CompilerMessageWindow : PCompilerMessageWindow = nil;
110 CompilerStatusDialog : PCompilerStatusDialog = nil;
111 CompileStamp : longint = 0;
112 RestartingDebugger : boolean = false;
113
114 procedure DoCompile(Mode: TCompileMode);
NeedRecompilenull115 function NeedRecompile(Mode :TCompileMode; verbose : boolean): boolean;
116 procedure ParseUserScreen;
117
118 procedure RegisterFPCompile;
119
120 const
121 CompilingHiddenFile : PSourceWindow = nil;
122
123 implementation
124
125 uses
126 {$ifdef Unix}
127 Unix, BaseUnix,
128 {$endif}
129 {$ifdef go32v2}
130 dpmiexcp,
131 {$endif}
132 {$ifdef Windows}
133 {$ifdef HasSignal}
134 signals,
135 {$endif}
136 {$endif}
137 { $ifdef HasSignal}
138 fpcatch,
139 { $endif HasSignal}
140 Dos,
141 Video,
142 globals,
143 StdDlg,App,tokens,
144 FVConsts,
145 CompHook, Compiler, systems, browcol,
146 WEditor,
147 FPRedir,FPDesk,
148 FPUsrScr,FPHelp,
149 {$ifndef NODEBUG}FPDebug,{$endif}
150 FPConst,FPVars,FPUtils,
151 FPCodCmp,FPIntf,FPSwitch;
152
153 {$ifndef NOOBJREG}
154 const
155 RCompilerMessageListBox: TStreamRec = (
156 ObjType: 1211;
157 VmtLink: Ofs(TypeOf(TCompilerMessageListBox)^);
158 Load: @TCompilerMessageListBox.Load;
159 Store: @TCompilerMessageListBox.Store
160 );
161 RCompilerMessageWindow: TStreamRec = (
162 ObjType: 1212;
163 VmtLink: Ofs(TypeOf(TCompilerMessageWindow)^);
164 Load: @TCompilerMessageWindow.Load;
165 Store: @TCompilerMessageWindow.Store
166 );
167 {$endif}
168 {$ifdef useresstrings}
169 resourcestring
170 {$else}
171 const
172 {$endif}
173 dialog_compilermessages = 'Compiler Messages';
174 dialog_compilingwithmode = 'Compiling (%s mode)';
175
176 { Compiler message classes }
177 msg_class_normal = '';
178 msg_class_fatal = 'Fatal';
179 msg_class_error = 'Error';
180 msg_class_warning = 'Warning';
181 msg_class_note = 'Note';
182 msg_class_hint = 'Hint';
183 msg_class_macro = 'Macro';
184 msg_class_procedure= 'Procedure';
185 msg_class_conditional = 'Conditional';
186 msg_class_info = 'Info';
187 msg_class_status = 'Status';
188 msg_class_used = 'Used';
189 msg_class_tried = 'Tried';
190 msg_class_debug = 'Debug';
191
192 { Compile status dialog texts }
193 msg_compilingfile = 'Compiling %s';
194 msg_loadingunit = 'Loading %s unit';
195 msg_linkingfile = 'Linking %s';
196 msg_compiledone = 'Done.';
197 msg_failedtocompile = 'Failed to compile...';
198 msg_compilationaborted = 'Compilation aborted...';
199
200 msg_nothingtocompile = 'Oooops, nothing to compile.';
201 msg_cantcompileunsavedfile = 'Can''t compile unsaved file.';
202
203 msg_couldnotcreatefile = 'could not create %s';
204 msg_therearemoreerrorsinfile = 'There are more errors in file %s';
205 msg_firstcompilationof = 'First compilation of %s';
206 msg_recompilingbecauseof = 'Recompiling because of %s';
207
208 msg_errorinexternalcompilation = 'Error in external compilation';
209 msg_iostatusis = 'IOStatus = %d';
210 msg_executeresultis = 'ExecuteResult = %d';
211
212 { Status hints during compilation }
213 msg_hint_pressesctocancel = 'Press ESC to cancel';
214 msg_hint_compilesuccessfulpressenter = 'Compile successful: ~Press any key~';
215 msg_hint_compilefailed = 'Compile failed';
216 msg_hint_compileaborted = 'Compile aborted';
217 msg_hint_pleasewait = 'Please wait...';
218
219 msg_cantopenfile = 'Can''t open %s';
220
221 procedure ParseUserScreen;
222 var
223 Y,YMax : longint;
224 LEvent : TEvent;
225 Text,Attr : String;
226 DisplayCompilerWindow : boolean;
227 cc: integer;
228
229 procedure SearchBackTrace;
230 var AText,ModuleName,st : String;
231 row : longint;
232 begin
233 if pos(' $',Text)=1 then
234 begin
235 AText:=Text;
236 Delete(Text,1,11);
237 While pos(' ',Text)=1 do
238 Delete(Text,1,1);
239 if pos('of ',Text)>0 then
240 begin
241 ModuleName:=Copy(Text,pos('of ',Text)+3,255);
242 While ModuleName[Length(ModuleName)]=' ' do
243 Delete(ModuleName,Length(ModuleName),1);
244 end
245 else
246 ModuleName:='';
247 if pos('line ',Text)>0 then
248 begin
249 Text:=Copy(Text,Pos('line ',Text)+5,255);
250 st:=Copy(Text,1,Pos(' ',Text)-1);
251 Val(st,row,cc);
252 end
253 else
254 row:=0;
255 CompilerMessageWindow^.AddMessage(V_Fatal or v_lineinfo,AText
256 ,ModuleName,row,1);
257 DisplayCompilerWindow:=true;
258 end;
259 end;
260
261 procedure InsertInMessages(Const TypeStr : String;_Type : longint;EnableDisplay : boolean);
262 var p,p2,col,row : longint;
263 St,ModuleName : string;
264
265 begin
266 p:=pos(TypeStr,Text);
267 p2:=Pos('(',Text);
268 if (p>0) and (p2>0) and (p2<p) then
269 begin
270 ModuleName:=Copy(Text,1,p2-1);
271 st:=Copy(Text,p2+1,255);
272 Val(Copy(st,1,pos(',',st)-1),row,cc);
273 st:=Copy(st,Pos(',',st)+1,255);
274 Val(Copy(st,1,pos(')',st)-1),col,cc);
275 CompilerMessageWindow^.AddMessage(_type,Copy(Text,pos(':',Text)+1,255)
276 ,ModuleName,row,col);
277 If EnableDisplay then
278 DisplayCompilerWindow:=true;
279 end;
280 end;
281
282 begin
283 if not assigned(UserScreen) then
284 exit;
285 DisplayCompilerWindow:=false;
286 YMax:=UserScreen^.GetHeight;
287 PushStatus('Parsing User Screen');
288 CompilerMessageWindow^.Lock;
289 for Y:=0 to YMax do
290 begin
291 UserScreen^.GetLine(Y,Text,Attr);
292 if (y mod 10) = 0 then
293 begin
294 CompilerMessageWindow^.Unlock;
295 SetStatus('Parsing User Screen line '+IntToStr(y)+'/'+IntToStr(YMax));
296 CompilerMessageWindow^.Lock;
297 end;
298 GetKeyEvent(LEvent);
299 if (LEvent.What=evKeyDown) and (LEvent.KeyCode=kbEsc) then
300 break;
301 SearchBackTrace;
302 InsertInMessages(' Fatal:',v_Fatal or v_lineinfo,true);
303 InsertInMessages(' Error:',v_Error or v_lineinfo,true);
304 InsertInMessages(' Warning:',v_Warning or v_lineinfo,false);
305 InsertInMessages(' Note:',v_Note or v_lineinfo,false);
306 InsertInMessages(' Info:',v_Info or v_lineinfo,false);
307 InsertInMessages(' Hint:',v_Hint or v_lineinfo,false);
308 end;
309 if DisplayCompilerWindow then
310 begin
311 if not CompilerMessageWindow^.GetState(sfVisible) then
312 CompilerMessageWindow^.Show;
313 CompilerMessageWindow^.MakeFirst;
314 CompilerMessageWindow^.MsgLB^.SelectFirstError;
315 end;
316 CompilerMessageWindow^.UnLock;
317 PopStatus;
318 end;
319
320 {*****************************************************************************
321 TCompilerMessage
322 *****************************************************************************}
323
TCompilerMessage.GetTextnull324 function TCompilerMessage.GetText(MaxLen: Sw_Integer): String;
325 var
326 ClassS: string[20];
327 S: string;
328 begin
329 case TClass and V_LevelMask of
330 V_Fatal : ClassS:=msg_class_Fatal;
331 V_Error : ClassS:=msg_class_Error;
332 V_Normal : ClassS:=msg_class_Normal;
333 V_Warning : ClassS:=msg_class_Warning;
334 V_Note : ClassS:=msg_class_Note;
335 V_Hint : ClassS:=msg_class_Hint;
336 {$ifdef VERBOSETXT}
337 V_Conditional : ClassS:=msg_class_conditional;
338 V_Info : ClassS:=msg_class_info;
339 V_Status : ClassS:=msg_class_status;
340 V_Used : ClassS:=msg_class_used;
341 V_Tried : ClassS:=msg_class_tried;
342 V_Debug : ClassS:=msg_class_debug;
343 else
344 ClassS:='???';
345 {$endif}
346 else
347 ClassS:='';
348 end;
349 if ClassS<>'' then
350 ClassS:=RExpand(ClassS,0)+': ';
351 if assigned(Module) and
352 ((TClass and V_LineInfo)=V_LineInfo) then
353 begin
354 if Row>0 then
355 begin
356 if Col>0 then
357 S:=NameAndExtOf(Module^)+'('+IntToStr(Row)+','+IntToStr(Col)+') '+ClassS
358 else
359 S:=NameAndExtOf(Module^)+'('+IntToStr(Row)+') '+ClassS;
360 end
361 else
362 S:=NameAndExtOf(Module^)+'('+IntToStr(Row)+') '+ClassS
363 end
364 else
365 S:=ClassS;
366 if assigned(Text) then
367 S:=S+Text^;
368 if length(S)>MaxLen then
369 S:=copy(S,1,MaxLen-2)+'..';
370 GetText:=S;
371 end;
372
373
374 {*****************************************************************************
375 TCompilerMessageListBox
376 *****************************************************************************}
377
GetPalettenull378 function TCompilerMessageListBox.GetPalette: PPalette;
379 const
380 P: string[length(CBrowserListBox)] = CBrowserListBox;
381 begin
382 GetPalette:=PPalette(@P);
383 end;
384
385 procedure TCompilerMessageListBox.SelectFirstError;
IsErrornull386 function IsError(P : PCompilerMessage) : boolean;
387 begin
388 IsError:=(P^.TClass and (V_Fatal or V_Error))<>0;
389 end;
390 var
391 P : PCompilerMessage;
392 begin
393 P:=List^.FirstThat(@IsError);
394 If Assigned(P) then
395 Begin
396 FocusItem(List^.IndexOf(P));
397 DrawView;
398 End;
399 end;
400
401
402 {*****************************************************************************
403 TCompilerMessageWindow
404 *****************************************************************************}
405
406 constructor TCompilerMessageWindow.Init;
407 var R: TRect;
408 HSB,VSB: PScrollBar;
409 begin
410 Desktop^.GetExtent(R);
411 R.A.Y:=R.B.Y-7;
412 inherited Init(R,dialog_compilermessages,{SearchFreeWindowNo}wnNoNumber);
413 HelpCtx:=hcCompilerMessagesWindow;
414
415 AutoNumber:=true;
416
417 HSB:=StandardScrollBar(sbHorizontal+sbHandleKeyboard);
418 HSB^.GrowMode:=gfGrowLoY+gfGrowHiX+gfGrowHiY;
419 Insert(HSB);
420 VSB:=StandardScrollBar(sbVertical+sbHandleKeyboard);
421 VSB^.GrowMode:=gfGrowLoX+gfGrowHiX+gfGrowHiY;
422 Insert(VSB);
423
424 GetExtent(R);
425 R.Grow(-1,-1);
426 New(MsgLB, Init(R, HSB, VSB));
427
428 MsgLB^.GrowMode:=gfGrowHiX+gfGrowHiY;
429 Insert(MsgLB);
430 CompilerMessageWindow:=@self;
431 end;
432
433
434 procedure TCompilerMessageWindow.AddMessage(AClass: longint;const Msg, Module: string; Line, Column: longint);
435 begin
436 if (AClass and V_LineInfo)<>V_LineInfo then
437 Line:=0;
438 MsgLB^.AddItem(New(PCompilerMessage,Init(AClass, Msg, MsgLB^.AddModuleName(Module), Line, Column)));
439 if (@Self=CompilerMessageWindow) and ((AClass = V_fatal) or (AClass = V_Error)) then
440 begin
441 if not GetState(sfVisible) then
442 Show;
443 if Desktop^.First<>PView(CompilerMessageWindow) then
444 MakeFirst;
445 end;
446 end;
447
448
449 procedure TCompilerMessageWindow.ClearMessages;
450 begin
451 MsgLB^.Clear;
452 ReDraw;
453 end;
454
455
456 {procedure TCompilerMessageWindow.Updateinfo;
457 begin
458 if CompileShowed then
459 begin
460 InfoST^.SetText(
461 RExpand(' Main file : '#1#$7f+Copy(SmartPath(MainFile),1,39),40)+#2+
462 'Total lines : '#1#$7e+IntToStr(Status.CompiledLines)+#2#13+
463 RExpand(' Target : '#1#$7f+KillTilde(TargetSwitches^.ItemName(TargetSwitches^.GetCurrSel)),40)+#2+
464 'Total errors : '#1#$7e+IntToStr(Status.ErrorCount)
465 );
466 if status.currentline>0 then
467 CurrST^.SetText(' Status: '#1#$7e+status.currentsource+'('+IntToStr(status.currentline)+')'#2)
468 else
469 CurrST^.SetText(' Status: '#1#$7e+status.currentsource+#2);
470 end;
471 ReDraw;
472 end;}
473
474
475 procedure TCompilerMessageWindow.HandleEvent(var Event: TEvent);
476 begin
477 case Event.What of
478 evBroadcast :
479 case Event.Command of
480 cmListFocusChanged :
481 if Event.InfoPtr=MsgLB then
482 Message(Application,evBroadcast,cmClearLineHighlights,@Self);
483 end;
484 end;
485 inherited HandleEvent(Event);
486 end;
487
488
489 procedure TCompilerMessageWindow.SizeLimits(var Min, Max: TPoint);
490 begin
491 inherited SizeLimits(Min,Max);
492 Min.X:=20;
493 Min.Y:=4;
494 end;
495
496
497 procedure TCompilerMessageWindow.Close;
498 begin
499 Hide;
500 end;
501
502
GetPalettenull503 function TCompilerMessageWindow.GetPalette: PPalette;
504 const
505 S : string[length(CBrowserWindow)] = CBrowserWindow;
506 begin
507 GetPalette:=PPalette(@S);
508 end;
509
510
511 constructor TCompilerMessageWindow.Load(var S: TStream);
512 begin
513 inherited Load(S);
514 GetSubViewPtr(S,MsgLB);
515 end;
516
517
518 procedure TCompilerMessageWindow.Store(var S: TStream);
519 begin
520 if MsgLB^.List=nil then
521 MsgLB^.NewList(New(PCollection, Init(100,100)));
522 inherited Store(S);
523 PutSubViewPtr(S,MsgLB);
524 end;
525
526 procedure TCompilerMessageWindow.UpdateCommands;
527 var Active: boolean;
528 begin
529 Active:=GetState(sfActive);
530 SetCmdState(CompileCmds,Active);
531 Message(Application,evBroadcast,cmCommandSetChanged,nil);
532 end;
533
534 procedure TCompilerMessageWindow.SetState(AState: Word; Enable: Boolean);
535 var OldState: word;
536 begin
537 OldState:=State;
538 inherited SetState(AState,Enable);
539 if ((AState and sfActive)<>0) and (((OldState xor State) and sfActive)<>0) then
540 UpdateCommands;
541 end;
542
543 destructor TCompilerMessageWindow.Done;
544 begin
545 CompilerMessageWindow:=nil;
546 inherited Done;
547 end;
548
549
550 {****************************************************************************
551 CompilerStatusDialog
552 ****************************************************************************}
553
getrealtimenull554 function getrealtime : real;
555 var
556 {$IFDEF USE_SYSUTILS}
557 h,m,s,s1000 : word;
558 {$ELSE USE_SYSUTILS}
559 h,m,s,s100 : word;
560 {$ENDIF USE_SYSUTILS}
561 begin
562 {$IFDEF USE_SYSUTILS}
563 DecodeTime(Time,h,m,s,s1000);
564 getrealtime:=h*3600.0+m*60.0+s+s1000/1000.0;
565 {$ELSE USE_SYSUTILS}
566 gettime(h,m,s,s100);
567 getrealtime:=h*3600.0+m*60.0+s+s100/100.0;
568 {$ENDIF USE_SYSUTILS}
569 end;
570
571 constructor TCompilerStatusDialog.Init;
572 var R: TRect;
573 begin
574 R.Assign(0,0,56,11);
575 ClearFormatParams; AddFormatParamStr(KillTilde(SwitchesModeName[SwitchesMode]));
576 inherited Init(R, FormatStrF(dialog_compilingwithmode, FormatParams));
577 starttime:=getrealtime;
578 GetExtent(R); R.B.Y:=11;
579 R.Grow(-3,-2);
580 New(ST, Init(R, ''));
581 Insert(ST);
582 GetExtent(R); R.B.Y:=11;
583 R.Grow(-1,-1); R.A.Y:=R.B.Y-1;
584 New(KeyST, Init(R, '', Blue*16+White+longint($80+Blue*16+White)*256,true));
585 Insert(KeyST);
586 { Reset Status infos see bug 1585 }
587 Fillchar(Status,SizeOf(Status),#0);
588 end;
589
590 destructor TCompilerStatusDialog.Done;
591 begin
592 if @Self=CompilerStatusDialog then
593 CompilerStatusDialog:=nil;
594 Inherited Done;
595 end;
596
597 procedure TCompilerStatusDialog.SetStartTime(r : real);
598 begin
599 starttime:=r;
600 end;
601
602 procedure TCompilerStatusDialog.Update;
603 var
604 StatusS,KeyS: string;
605 hstatus : TFPCHeapStatus;
606 r : real;
607 const
608 MaxFileNameSize = 46;
609 begin
610 case CompilationPhase of
611 cpCompiling :
612 begin
613 ClearFormatParams;
614 if Upcase(Status.currentmodulestate)='COMPILE' then
615 begin
616 AddFormatParamStr(ShrinkPath(SmartPath(Status.Currentsourcepath+Status.CurrentSource),
617 MaxFileNameSize - Length(msg_compilingfile)));
618 StatusS:=FormatStrF(msg_compilingfile,FormatParams);
619 end
620 else
621 begin
622 if Status.CurrentSource='' then
623 StatusS:=' '
624 else
625 begin
626 StatusS:=ShrinkPath(SmartPath(DirAndNameOf(Status.Currentsourcepath+Status.CurrentSource)),
627 MaxFileNameSize-Length(msg_loadingunit));
628 AddFormatParamStr(StatusS);
629 StatusS:=FormatStrF(msg_loadingunit,FormatParams);
630 end;
631 end;
632 KeyS:=msg_hint_pressesctocancel;
633 end;
634 cpLinking :
635 begin
636 ClearFormatParams;
637 AddFormatParamStr(ShrinkPath(ExeFile,
638 MaxFileNameSize-Length(msg_linkingfile)));
639 StatusS:=FormatStrF(msg_linkingfile,FormatParams);
640 KeyS:=msg_hint_pleasewait;
641 end;
642 cpDone :
643 begin
644 StatusS:=msg_compiledone;
645 KeyS:=msg_hint_compilesuccessfulpressenter;
646 end;
647 cpFailed :
648 begin
649 StatusS:=msg_failedtocompile;
650 KeyS:=msg_hint_compilefailed;
651 end;
652 cpAborted :
653 begin
654 StatusS:=msg_compilationaborted;
655 KeyS:=msg_hint_compileaborted;
656 end;
657 end;
658 ClearFormatParams;
659 AddFormatParamStr(ShrinkPath(SmartPath(MainFile),
660 MaxFileNameSize-Length('Main file: %s')));
661 AddFormatParamStr(StatusS);
662 AddFormatParamStr(KillTilde(TargetSwitches^.ItemName(TargetSwitches^.GetCurrSel)));
663 AddFormatParamInt(Status.CurrentLine);
664 AddFormatParamInt(Status.CompiledLines);
665 hstatus:=GetFPCHeapStatus;
666 AddFormatParamInt(hstatus.CurrHeapUsed div 1024);
667 AddFormatParamInt(hstatus.CurrHeapSize div 1024);
668 AddFormatParamInt(Status.ErrorCount);
669 r:=getrealtime;
670 AddFormatParamInt(trunc(r-starttime));
671 AddFormatParamInt(trunc(frac(r-starttime)*10));
672 ST^.SetText(
673 FormatStrF(
674 'Main file: %s'#13+
675 '%s'+#13#13+
676 'Target: %s'#13+
677 'Line number: %6d '+'Total lines: %6d'+#13+
678 'Used memory: %6dK '+'Allocated memory: %6dK'#13+
679 'Total errors:%6d '+'Compile time: %8d.%1ds',
680 FormatParams)
681 );
682 KeyST^.SetText(^C+KeyS);
683 end;
684
685
686 {****************************************************************************
687 Compiler Hooks
688 ****************************************************************************}
689
690 const
691 lasttime : real = 0;
692
CompilerStatusnull693 function CompilerStatus: boolean;
694 var
695 event : tevent;
696
697 begin
698 GetKeyEvent(Event);
699 if (Event.What=evKeyDown) and (Event.KeyCode=kbEsc) then
700 begin
701 CompilationPhase:=cpAborted;
702 { update info messages }
703 if assigned(CompilerStatusDialog) then
704 begin
705 {$ifdef redircompiler}
706 RedirDisableAll;
707 {$endif}
708 CompilerStatusDialog^.Update;
709 {$ifdef redircompiler}
710 RedirEnableAll;
711 {$endif}
712 end;
713 CompilerStatus:=true;
714 exit;
715 end;
716 { only display line info every 100 lines, ofcourse all other messages
717 will be displayed directly }
718 if (getrealtime-lasttime>=CompilerStatusUpdateDelay) or (status.compiledlines=1) then
719 begin
720 lasttime:=getrealtime;
721 { update info messages }
722 {$ifdef redircompiler}
723 RedirDisableAll;
724 {$endif}
725 if assigned(CompilerStatusDialog) then
726 CompilerStatusDialog^.Update;
727 {$ifdef redircompiler}
728 RedirEnableAll;
729 {$endif}
730 { update memory usage }
731 { HeapView^.Update; }
732 end;
733 CompilerStatus:=false;
734 end;
735
CompilerGetNamedFileTimenull736 Function CompilerGetNamedFileTime(const filename : ansistring) : Longint;
737 var t: longint;
738 W: PSourceWindow;
739 begin
740 W:=EditorWindowFile(FExpand(filename));
741 if Assigned(W) and (W^.Editor^.GetModified) then
742 t:=Now
743 else
744 t:=def_getnamedfiletime(filename);
745 CompilerGetNamedFileTime:=t;
746 end;
747
CompilerOpenInputFilenull748 function CompilerOpenInputFile(const filename: ansistring): tinputfile;
749 var f: tinputfile;
750 W: PSourceWindow;
751 begin
752 if assigned(CompilingHiddenFile) and
753 (NameandExtof(filename)=CompilingHiddenFile^.Editor^.Filename) then
754 W:=CompilingHiddenFile
755 else
756 W:=EditorWindowFile(FExpand(filename));
757 if Assigned(W) and (W^.Editor^.GetModified) then
758 f:=TFPInputFile.Create(W^.Editor)
759 else
760 f:=def_openinputfile(filename);
761 if assigned(W) then
762 W^.Editor^.CompileStamp:=CompileStamp;
763 CompilerOpenInputFile:=f;
764 end;
765
CompilerCommentnull766 function CompilerComment(Level:Longint; const s:ansistring):boolean;
767 begin
768 CompilerComment:=false;
769 if (status.verbosity and Level)<>0 then
770 begin
771 {$ifdef redircompiler}
772 RedirDisableAll;
773 {$endif}
774
775 if not CompilerMessageWindow^.GetState(sfVisible) then
776 CompilerMessageWindow^.Show;
777 if Desktop^.First<>PView(CompilerMessageWindow) then
778 CompilerMessageWindow^.MakeFirst;
779 CompilerMessageWindow^.AddMessage(Level,S,status.currentsourcepath+status.currentsource,
780 status.currentline,status.currentcolumn);
781 { update info messages }
782 if assigned(CompilerStatusDialog) then
783 CompilerStatusDialog^.Update;
784 {$ifdef redircompiler}
785 RedirEnableAll;
786 {$endif}
787 { update memory usage }
788 { HeapView^.Update; }
789 end;
790 end;
791
792
793 {****************************************************************************
794 DoCompile
795 ****************************************************************************}
796
797 { This function must return '' if
798 "Options|Directories|Exe and PPU directory" is empty }
GetExePathnull799 function GetExePath: string;
800 var Path: string;
801 I: Sw_integer;
802 begin
803 Path:='';
804 if DirectorySwitches<>nil then
805 with DirectorySwitches^ do
806 for I:=0 to ItemCount-1 do
807 begin
808 if ItemParam(I)='-FE' then
809 begin
810 Path:=GetStringItem(I);
811 Break;
812 end;
813 end;
814 if Path<>'' then
815 GetExePath:=CompleteDir(FExpand(Path))
816 else
817 GetExePath:='';
818 end;
819
GetMainFilenull820 function GetMainFile(Mode: TCompileMode): string;
821 var FileName: string;
822 P : PSourceWindow;
823 begin
824 if assigned(CompilingHiddenFile) then
825 P:=CompilingHiddenFile
826 else
827 P:=Message(Desktop,evBroadcast,cmSearchWindow,nil);
828 if (PrimaryFileMain='') and (P=nil) then
829 FileName:='' { nothing to compile }
830 else
831 begin
832 if (PrimaryFileMain<>'') and (Mode<>cCompile) then
833 FileName:=PrimaryFileMain
834 else if assigned(P) then
835 begin
836 FileName:=P^.Editor^.FileName;
837 if FileName='' then
838 begin
839 P^.Editor^.SaveAsk(true);
840 FileName:=P^.Editor^.FileName;
841 end;
842 end
843 else
844 FileName:='';
845 end;
846 {$ifdef Unix}
847 If (FileName<>'') then
848 FileName:=FExpand(FileName);
849 {$else}
850 If (FileName<>'') then
851 FileName:=FixFileName(FExpand(FileName));
852 {$endif}
853 GetMainFile:=FileName;
854 end;
855
856 procedure ResetErrorMessages;
857 procedure ResetErrorLine(P: PView);
858 begin
859 if assigned(P) and
860 (TypeOf(P^)=TypeOf(TSourceWindow)) then
861 PSourceWindow(P)^.Editor^.SetErrorMessage('');
862 end;
863 begin
864 Desktop^.ForEach(@ResetErrorLine);
865 end;
866
867
868 procedure DoCompile(Mode: TCompileMode);
869
IsExitEventnull870 function IsExitEvent(E: TEvent): boolean;
871 begin
872 { following suggestion by Harsha Senanayake }
873 IsExitEvent:=(E.What=evKeyDown);
874 end;
GetTargetExeExtnull875 function GetTargetExeExt : string;
876 begin
877 GetTargetExeExt:=target_info.exeext;
878 end;
879 var
880 s,FileName: string;
881 ErrFile : Text;
882 MustRestartDebugger : boolean;
883 Error,LinkErrorCount : longint;
884 E : TEvent;
885 DummyView: PView;
886 PPasFile : string[64];
887 begin
888 AskRecompileIfModifiedFlag:=true;
889 { Get FileName }
890 FileName:=GetMainFile(Mode);
891 if FileName='' then
892 begin
893 ErrorBox(msg_nothingtocompile,nil);
894 Exit;
895 end else
896 { THis is not longer necessary as unsaved files are loaded from a memorystream,
897 and with the file as primaryfile set it is already incompatible with itself
898 if FileName='*' then
899 begin
900 ErrorBox(msg_cantcompileunsavedfile,nil);
901 Exit;
902 end; }
903 PushStatus('Beginning compilation...');
904 { Show Compiler Messages Window }
905 { if not CompilerMessageWindow^.GetState(sfVisible) then
906 CompilerMessageWindow^.Show;
907 CompilerMessageWindow^.MakeFirst;}
908 CompilerMessageWindow^.ClearMessages;
909 { Tell why we compile }
910 NeedRecompile(Mode,true);
911
912 MainFile:=FileName;
913 SetStatus('Writing switches to file...');
914 WriteSwitches(SwitchesPath);
915 { leaving open browsers leads to crashes !! (PM) }
916 SetStatus('Preparing symbol info...');
917 CloseAllBrowsers;
918 if ((DesktopFileFlags and dfSymbolInformation)<>0) then
919 WriteSymbolsFile(BrowserName);
920 { MainFile:=FixFileName(FExpand(FileName));}
921 SetStatus('Preparing to compile...'+NameOf(MainFile));
922 { Reset }
923 CtrlBreakHit:=false;
924 { Create Compiler Status Dialog }
925 CompilationPhase:=cpCompiling;
926 if not assigned(CompilingHiddenFile) then
927 begin
928 New(CompilerStatusDialog, Init);
929 CompilerStatusDialog^.SetStartTime(getrealtime);
930 CompilerStatusDialog^.SetState(sfModal,true);
931 { disable window closing }
932 CompilerStatusDialog^.Flags:=CompilerStatusDialog^.Flags and not wfclose;
933 Application^.Insert(CompilerStatusDialog);
934 CompilerStatusDialog^.Update;
935 end;
936 { Restore dir that could be changed during debugging }
937 {$I-}
938 ChDir(StartUpDir);
939 {$I+}
940 EatIO;
941 { hook compiler output }
942 do_status:=@CompilerStatus;
943 do_comment:=@CompilerComment;
944 do_openinputfile:=@CompilerOpenInputFile;
945 do_getnamedfiletime:=@CompilerGetNamedFileTime;
946 do_initsymbolinfo:=@InitBrowserCol;
947 do_donesymbolinfo:=@DoneBrowserCol;
948 do_extractsymbolinfo:=@CreateBrowserCol;
949 { Compile ! }
950 {$ifdef redircompiler}
951 ChangeRedirOut(FPOutFileName,false);
952 ChangeRedirError(FPErrFileName,false);
953 {$endif}
954 { insert "" around name so that spaces are allowed }
955 { only supported in compiler after 2000/01/14 PM }
956 if pos(' ',FileName)>0 then
957 FileName:='"'+FileName+'"';
958 if mode=cBuild then
959 FileName:='-B '+FileName;
960 { tokens are created and distroed by compiler.compile !! PM }
961 DoneTokens;
962 PPasFile:='ppas'+source_info.scriptext;
963 WUtils.DeleteFile(GetExePath+PpasFile);
964 SetStatus('Compiling...');
965 inc(CompileStamp);
966 ResetErrorMessages;
967 {$ifndef NODEBUG}
968 MustRestartDebugger:=false;
969 if assigned(Debugger) then
970 if Debugger^.HasExe then
971 begin
972 Debugger^.Reset;
973 MustRestartDebugger:=true;
974 end;
975 {$endif NODEBUG}
976 try
977 FpIntF.Compile(FileName,SwitchesPath);
978 except
979 on ECompilerAbort do
980 CompilerMessageWindow^.AddMessage(V_error,'Error during compilation','',0,0);
981 on E:Exception do
982 CompilerMessageWindow^.AddMessage(V_error,E.Message+' during compilation','',0,0);
983 end;
984 SetStatus('Finished compiling...');
985
986 { Retrieve created exefile }
987 If GetEXEPath<>'' then
988 EXEFile:=FixFileName(GetEXEPath+NameOf(MainFile)+GetTargetExeExt)
989 else
990 EXEFile:=DirOf(MainFile)+NameOf(MainFile)+GetTargetExeExt;
991 DefaultReplacements(ExeFile);
992 { tokens are created and distroyed by compiler.compile !! PM }
993 InitTokens;
994 if LinkAfter and
995 ExistsFile(GetExePath+PpasFile) and
996 (CompilationPhase<>cpAborted) and
997 (status.errorCount=0) then
998 begin
999 CompilationPhase:=cpLinking;
1000 if assigned(CompilerStatusDialog) then
1001 CompilerStatusDialog^.Update;
1002 SetStatus('Assembling and/or linking...');
1003 {$ifndef redircompiler}
1004 { At least here we want to catch output
1005 of batch file PM }
1006 ChangeRedirOut(FPOutFileName,false);
1007 ChangeRedirError(FPErrFileName,false);
1008 {$endif}
1009 {$ifdef Unix}
1010 error:=0;
1011 If fpsystem(GetExePath+PpasFile)=-1 Then
1012 Error:=fpgeterrno;
1013 {$else}
1014 DosExecute(GetEnv('COMSPEC'),'/C '+GetExePath+PpasFile);
1015 Error:=DosError;
1016 {$endif}
1017 SetStatus('Finished linking...');
1018 RestoreRedirOut;
1019 RestoreRedirError;
1020 if Error<>0 then
1021 Inc(status.errorCount);
1022 if Status.IsExe and not Status.IsLibrary and not ExistsFile(EXEFile) then
1023 begin
1024 Inc(status.errorCount);
1025 ClearFormatParams; AddFormatParamStr(ExeFile);
1026 CompilerMessageWindow^.AddMessage(V_error,FormatStrF(msg_couldnotcreatefile,FormatParams),'',0,0);
1027 {$I-}
1028 Assign(ErrFile,FPErrFileName);
1029 Reset(ErrFile);
1030 if EatIO<>0 then
1031 ErrorBox(FormatStrStr(msg_cantopenfile,FPErrFileName),nil)
1032 else
1033 begin
1034 LinkErrorCount:=0;
1035 While not eof(ErrFile) and (LinkErrorCount<25) do
1036 begin
1037 readln(ErrFile,s);
1038 CompilerMessageWindow^.AddMessage(V_error,s,'',0,0);
1039 inc(LinkErrorCount);
1040 end;
1041 if not eof(ErrFile) then
1042 begin
1043 ClearFormatParams; AddFormatParamStr(FPErrFileName);
1044 CompilerMessageWindow^.AddMessage(V_error,
1045 FormatStrF(msg_therearemoreerrorsinfile,FormatParams),'',0,0);
1046 end;
1047
1048 Close(ErrFile);
1049 end;
1050 EatIO;
1051 {$I+}
1052 end
1053 else if error=0 then
1054 WUtils.DeleteFile(GetExePath+PpasFile);
1055 end;
1056 {$ifdef redircompiler}
1057 RestoreRedirOut;
1058 RestoreRedirError;
1059 {$endif}
1060 PopStatus;
1061 { Set end status }
1062 if not (CompilationPhase in [cpAborted,cpFailed]) then
1063 if (status.errorCount=0) then
1064 begin
1065 CompilationPhase:=cpDone;
1066 LastCompileTime := cardinal(Now);
1067 end
1068 else
1069 CompilationPhase:=cpFailed;
1070 { Show end status }
1071 { reenable window closing }
1072 if assigned(CompilerStatusDialog) then
1073 begin
1074 CompilerStatusDialog^.Flags:=CompilerStatusDialog^.Flags or wfclose;
1075 CompilerStatusDialog^.Update;
1076 CompilerStatusDialog^.ReDraw;
1077 CompilerStatusDialog^.SetState(sfModal,false);
1078 if ((CompilationPhase in [cpAborted,cpDone,cpFailed]) or (ShowStatusOnError))
1079 and ((Mode<>cRun) or (CompilationPhase<>cpDone)) then
1080 repeat
1081 CompilerStatusDialog^.GetEvent(E);
1082 if IsExitEvent(E)=false then
1083 CompilerStatusDialog^.HandleEvent(E);
1084 until IsExitEvent(E) or not assigned(CompilerStatusDialog);
1085 {if IsExitEvent(E) then
1086 Application^.PutEvent(E);}
1087 if assigned(CompilerStatusDialog) then
1088 begin
1089 Application^.Delete(CompilerStatusDialog);
1090 Dispose(CompilerStatusDialog, Done);
1091 end;
1092 end;
1093 CompilerStatusDialog:=nil;
1094 { end compilation returns true if the messagewindow should be removed }
1095 if CompilationPhase=cpDone then
1096 begin
1097 CompilerMessageWindow^.Hide;
1098 { This is the last compiled main file }
1099 PrevMainFile:=MainFile;
1100 MainHasDebugInfo:=DebugInfoSwitches^.GetCurrSelParam<>'-';
1101 end;
1102 { Update the app }
1103 Message(Application,evCommand,cmUpdate,nil);
1104 DummyView:=Desktop^.First;
1105 while (DummyView<>nil) and (DummyView^.GetState(sfVisible)=false) do
1106 begin
1107 DummyView:=DummyView^.NextView;
1108 end;
1109 with DummyView^ do
1110 if GetState(sfVisible) then
1111 begin
1112 SetState(sfSelected,false);
1113 SetState(sfSelected,true);
1114 end;
1115 if Assigned(CompilerMessageWindow) then
1116 with CompilerMessageWindow^ do
1117 begin
1118 if GetState(sfVisible) then
1119 begin
1120 SetState(sfSelected,false);
1121 SetState(sfSelected,true);
1122 end;
1123 if (status.errorCount>0) then
1124 MsgLB^.SelectFirstError;
1125 end;
1126 { ^^^ we need this trick to reactivate the desktop }
1127 EditorModified:=false;
1128 {$ifndef NODEBUG}
1129 if MustRestartDebugger then
1130 InitDebugger;
1131 {$endif NODEBUG}
1132 { In case we have something that the compiler touched }
1133 AskToReloadAllModifiedFiles;
1134 { Try to read Browser info in again if compilation failure !! }
1135 if Not Assigned(Modules) and (CompilationPhase<>cpDone) and
1136 ((DesktopFileFlags and dfSymbolInformation)<>0) then
1137 ReadSymbolsFile(BrowserName);
1138 if UseAllUnitsInCodeComplete and not assigned(CompilingHiddenFile) then
1139 AddAvailableUnitsToCodeComplete(false);
1140 end;
1141
NeedRecompilenull1142 function NeedRecompile(Mode :TCompileMode; verbose : boolean): boolean;
1143 var Need: boolean;
1144 I: sw_integer;
1145 SF: PSourceFile;
1146 SourceTime,PPUTime,ObjTime: longint;
1147 W: PSourceWindow;
1148 begin
1149 if Assigned(SourceFiles)=false then
1150 Need:={(EditorModified=true)}true
1151 else
1152 begin
1153 Need:=(PrevMainFile<>GetMainFile(Mode)) and (PrevMainFile<>'');
1154 if Need then
1155 begin
1156 if verbose then
1157 begin
1158 ClearFormatParams; AddFormatParamStr(GetMainFile(Mode));
1159 CompilerMessageWindow^.AddMessage(V_info,
1160 FormatStrF(msg_firstcompilationof,FormatParams),
1161 '',0,0);
1162 end;
1163 end
1164 else
1165 for I:=0 to SourceFiles^.Count-1 do
1166 begin
1167 SF:=SourceFiles^.At(I);
1168 SourceTime:=wutils.GetFileTime(SF^.GetSourceFileName);
1169 PPUTime:=wutils.GetFileTime(SF^.GetPPUFileName);
1170 ObjTime:=wutils.GetFileTime(SF^.GetObjFileName);
1171 { writeln('S: ',SF^.GetSourceFileName,' - ',SourceTime);
1172 writeln('P: ',SF^.GetPPUFileName,' - ',PPUTime);
1173 writeln('O: ',SF^.GetObjFileName,' - ',ObjTime);
1174 writeln('------');}
1175 { some units don't generate object files }
1176 W:=EditorWindowFile(SF^.GetSourceFileName);
1177 if (SourceTime<>-1) then
1178 if ((SourceTime>PPUTime) or
1179 ((SourceTime>ObjTime) and
1180 (ObjTime<>-1))) or
1181 (assigned(W) and (W^.Editor^.CompileStamp<0)) then
1182 begin
1183 Need:=true;
1184 if verbose then
1185 begin
1186 ClearFormatParams; AddFormatParamStr(SF^.GetSourceFileName);
1187 CompilerMessageWindow^.AddMessage(V_info,
1188 FormatStrF(msg_recompilingbecauseof,FormatParams),
1189 SF^.GetSourceFileName,1,1);
1190 end;
1191 Break;
1192 end;
1193 end;
1194 { writeln('Need?', Need); system.readln;}
1195 end;
1196
1197 NeedRecompile:=Need;
1198 end;
1199
1200
1201 constructor TFPInputFile.Create(AEditor: PFileEditor);
1202 begin
1203 if not Assigned(AEditor) then Fail;
1204 if inherited Create(AEditor^.FileName)=nil then
1205 Fail;
1206 Editor:=AEditor;
1207 end;
1208
1209
fileopennull1210 function TFPInputFile.fileopen(const filename: ansistring): boolean;
1211 var OK: boolean;
1212 begin
1213 S:=New(PMemoryStream, Init(0,0));
1214 OK:=Assigned(S) and (S^.Status=stOK);
1215 if OK then OK:=Editor^.SaveToStream(S);
1216 if OK then
1217 S^.Seek(0)
1218 else
1219 begin
1220 if Assigned(S) then Dispose(S, Done);
1221 S:=nil;
1222 end;
1223 fileopen:=OK;
1224 end;
1225
fileseeknull1226 function TFPInputFile.fileseek(pos: longint): boolean;
1227 var OK: boolean;
1228 begin
1229 OK:=assigned(S);
1230 if OK then
1231 begin
1232 S^.Reset;
1233 S^.Seek(pos);
1234 OK:=(S^.Status=stOK);
1235 end;
1236 fileseek:=OK;
1237 end;
1238
filereadnull1239 function TFPInputFile.fileread(var databuf; maxsize: longint): longint;
1240 var
1241 size: longint;
1242 begin
1243 if not assigned(S) then size:=0 else
1244 begin
1245 size:=min(maxsize,(S^.GetSize-S^.GetPos));
1246 S^.Read(databuf,size);
1247 if S^.Status<>stOK then size:=0;
1248 end;
1249 fileread:=size;
1250 end;
1251
TFPInputFile.fileeofnull1252 function TFPInputFile.fileeof: boolean;
1253 var EOF: boolean;
1254 begin
1255 EOF:=not assigned(S);
1256 if not EOF then
1257 EOF:=(S^.Status<>stOK) or (S^.GetPos=S^.GetSize);
1258 fileeof:=EOF;
1259 end;
1260
fileclosenull1261 function TFPInputFile.fileclose: boolean;
1262 var OK: boolean;
1263 begin
1264 OK:=assigned(S);
1265 if OK then
1266 begin
1267 S^.Reset;
1268 Dispose(S, Done);
1269 S:=nil;
1270 OK:=true;
1271 end;
1272 fileclose:=OK;
1273 end;
1274
1275 procedure tfpinputfile.filegettime;
1276 var
1277 dt : datetime;
1278 hsec,wday : word;
1279 begin
1280 { current time }
1281 dos.getdate(dt.year,dt.month,dt.day,wday);
1282 dos.gettime(dt.hour,dt.min,dt.sec,hsec);
1283 packtime(dt,filetime);
1284 end;
1285
1286 procedure RegisterFPCompile;
1287 begin
1288 {$ifndef NOOBJREG}
1289 RegisterType(RCompilerMessageListBox);
1290 RegisterType(RCompilerMessageWindow);
1291 {$endif}
1292 end;
1293
1294
1295 end.
1296